Documentation


JSON solution format

JSON (or JavaScript Object Notation) is a lightweight, text-based, language-independent data interchange format. It was derived from JavaScript, but many modern programming languages include code to generate and parse JSON-format data.

Gurobi JSON solution format is meant to be a simple and standard way to capture and share optimization results. It conforms to the RFC-8259 standard. JSON solutions can be written to a file or captured in a string.

The JSON solution captures the values of various Gurobi attributes associated with the solution to the model. Some are related to the model overall, some to individual variables, and some to individual constraints. The exact contents of a JSON solution string will depend on a few factors:

  • The type of model being solved (linear, quadratic, mixed-integer, multi-objective, etc.). Some solution information is simply not available for certain problem types (e.g., dual variable values for MIP models).
  • The set of tagged elements in the model. Users can tag variables (using the VTag attribute), linear constraints (using the CTag attribute), and quadratic constraints (using the QCTag attribute). Only tagged elements will have solution information in the JSON solution.
  • The JSONSolDetail parameter, which controls how much detail is included in the JSON solution.
  • Parameter settings such as InfUnbdInfo or QCPDual, which cause the optimization process to generate more solution information.

JSON solutions aren't generally meant to be interpreted directly by humans. Instead, you typically feed them into a JSON parser, which provides tools for extracting the desired information from the string. JSON is a widely-used format, and nearly all modern program languages have libraries available for helping to parse JSON strings and files. And if you are determined to examine the string directly, JSON parsers typically also include pretty-printing utilities that make it easier to do so.

Basic Structure

A JSON solution string consists of a collection of named components. In its simplest form, it might look like the following:

{ "SolutionInfo": { "Status": 3,
                    "Runtime": "3.4289908409118652e-01",
                    "BoundVio": "0",
                    "ConstrVio": "0",
                    "IterCount": "0",
                    "BarIterCount": 0}}
A JSON parser makes it relatively easy to extract the various components from this string. In Python, for example, you would be able to retrieve the optimization status by accessing result['SolutionInfo']['Status'] after parsing.

Before discussing the specific information that is available in this format, let us first say a word about how data is represented. The type of each data item follows from the attribute type. For example, Status is an integer attribute, so the corresponding value is stored as an integer. Runtime is a double attribute, which is represented as a string, and that string always captures the exact, double-precision (IEEE754) value of the attribute.

Named Components

A JSON solution will always have at least one named object: SolutionInfo. It may contain up to three optional named arrays: Vars, Constrs, QConstrs. A JSON solution string may look like:

{"SolutionInfo": {...},
 "Vars": [...],
 "Constrs": [...],
 "QConstrs": [...]}
The exact contents of the three optional sections will depend on what model components have been tagged and on what solution information is available. If no variables have been tagged, for example, then the Vars array will not be present. For a MIP model, the Constrs array will not be present, since MIP solutions don't contain any constraint information.

SolutionInfo Object

The SolutionInfo object contains high-level information about the solution that was computed for this model. Some entries will always be present, while others depend on the problem type or the results of the optimization. This component may include the following model attributes:

Status (always present)
The optimization status (optimal, infeasible, hit the time limit, etc.).
Runtime (always present)
Runtime for the optimization (in seconds).
ObjVal
The solution objective value.
ObjBound
The best known bound on the objective value.
ObjBoundC
The best known bound on the objective value (before using integrality information to strengthen the bound).
MIPGap
The optimality gap.
IntVio
The maximum integrality violation.
BoundVio
The maximum bound violation.
ConstrVio
The maximum constraint violation.
ObjNVal (multi-objective only)
An array of objective values, one for each objective.
ScenNObjVal (multi-scenario only)
An array of objective values, one for each scenario.
ScenNObjBound (multi-scenario only)
An array of objective bounds, one for each scenario.
IterCount
Number of simplex iterations.
BarIterCount
Number of barrier iterations.
NodeCount
Number of branch-and-cut nodes explored for MIP models.
FarkasProof
Part of the infeasibility certificate for infeasible models. Note that you have to set the InfUnbdInfo parameter before the optimization call for this information to be available.
SolCount
Number of stored solutions (only for MIP models).
PoolObjBound
Bound on the objective of undiscovered MIP solutions.
PoolObjVal
Only for MIP models with at least one solution. For single-objective models, this is an array containing the objective value for each stored solution (starting with the incumbent). For multi-objective models, this is an array containing SolCount arrays of values, each array contains the objective value for each multi-objective for the particular solution.

Here's an example of a SolutionInfo object for a MIP model:

{ "SolutionInfo": { "Status": 2,
                    "Runtime": "5.8451418876647949e+00",
                    "ObjVal": "3089",
                    "ObjBound": "3089",
                    "ObjBoundC": "3089",
                    "MIPGap": "0",
                    "IntVio": "0",
                    "BoundVio": "0",
                    "ConstrVio": "0",
                    "IterCount": "32",
                    "BarIterCount": 0,
                    "NodeCount": "1",
                    "SolCount": 1,
                    "PoolObjBound": "3089",
                    "PoolObjVal": [ "3089"]}}

Vars Array

The Vars component is an array (possibly empty) of objects containing information about tagged variables. Some entries will always be present, while others depend on the problem type or the results of the optimization. This component may include the following variable attributes:

VTag (always present)
Array containing the variable tag. Note that this is stored as an array, but the array will currently only ever contain a single string.
X (always present)
Value for the variable in the current solution.
Xn
Values for all stored solutions including the incumbent solution (only for MIP).
ScenNX
For multiple scenarios, values for all scenario solutions.
RC
For continuous models with dual information, the reduced cost for the variable.
VBasis
For continuous models whose solution is basic, the basis status for the variable.
UnbdRay
For unbounded models with InfUnbdInfo enabled, the unbounded ray component associated with the variable.

The following attributes are only included if JSONSolDetail is greater than 0: RC, UnbdRay, VBasis, Xn.

These objects may look like:

{ "VTag": ["VTag7"], "X": "1"}
{ "VTag": ["VTag12"], "X": "3.6444895037909271e-02", "RC": "0"}
{ "VTag": ["VTag2747"],
  "X": "0",
  "Xn": [ "0", "1", "1", "1", "0", "1", "1", "0", "0", "0"]}

Constrs Array

The Constrs component is an array (possibly empty) of objects containing information about tagged linear constraints. Some entries will always be present, while others depend on the problem type or the results of the optimization. This component may include the following constraint attributes:

CTag (always present)
Array containing the linear constraint tag. Note that this is stored as an array, but the array will currently only ever contain a single string.
Slack (always present)
Value for the slack variable in the current solution.
Pi
For continuous models with dual information, the dual value for the corresponding constraint.
FarkasDual
For infeasible models with InfUnbdInfo enabled, the Farkas dual component associated with the constraint.
This component will always be empty for MIP models.

The following attributes are only included if JSONSolDetail is greater than 0: CBasis, FarkasDual, Pi, Slack.

These objects may look like:

{ "CTag": ["CTag72"],
  "Slack": "-1.3877787807814457e-17",
  "Pi": "-5.6530866311690423e-02"}

QConstrs Array

The QConstrs component is an array (possibly empty) of objects containing information about tagged quadratic constraints. Some entries will always be present, while others depend on the problem type or the results of the optimization. This component may include the following quadratic constraint attributes:

QCTag (always present)
Array containing the quadratic constraint tag. Note that this is stored as an array, but the array will currently only ever contain a single string.
QCSlack (always present)
Value for the slack variable in the current solution.
QCPi
For continuous models with dual information, the dual value for the corresponding constraint.
This component will always be empty for MIP models.

The following attributes are only included if JSONSolDetail is greater than 0: QCPi, QCSlack.

JSON Solution Examples

For a continuous model, the JSON solution string may look like

{ "SolutionInfo": {
     "Status": 2,
     "Runtime": "9.9294495582580566e-01",
     "ObjVal": "5.2045497375374854e-07",
     "BoundVio": "0",
     "ConstrVio": "1.002e-07",
     "IterCount": "0",
     "BarIterCount": 3},
  "Vars": [
     {"VTag": ["VTag7"], "X": "-3.0187172916263982e-09", "RC": "0"},
     {"VTag": ["VTag1340"], "X": "-3.0696132844593768e-09", "RC": "0"},
     {"VTag": ["VTag2673"], "X": "-4.8134359014615295e-09", "RC": "0"},
     {"VTag": ["VTag4006"], "X": "-7.1652420015125937e-02", "RC": "0"},
     {"VTag": ["VTag5339"], "X": "-1.5815441619302997e-02", "RC": "0"},
     {"VTag": ["VTag6672"], "X": "1.4945278866946186e-02", "RC": "0"}],
  "Constrs": [
     {"CTag": ["CTag7"], "Slack": "4.85722506e-17", "Pi": "2.3140310696e-06"},
     {"CTag": ["CTag673"], "Slack": "0", "Pi": "-1.4475853138350041e-06"},
     {"CTag": ["CTag1339"], "Slack": "-2.7758914e-17", "Pi": "-3.7443785e-06"},
     {"CTag": ["CTag2005"], "Slack": "4.3420177e-18", "Pi": "-1.0277524e-06"},
     {"CTag": ["CTag2671"], "Slack": "-1.3895245e-17", "Pi": "8.0012944e-07"},
     {"CTag": ["CTag3337"], "Slack": "6.39465e-16", "Pi": "-5.3368958e-06"}]}

For a multi-objective LP, the JSON solution string may look like

{ "SolutionInfo": {
     "Status": 2,
     "Runtime": "2.2838807106018066e-01",
     "ObjNVal": [ "10", "339"],
     "IterCount": "112",
     "BarIterCount": 0,
     "NodeCount": "0"},
  "Vars": [
     {"VTag": ["VTag7"], "X": "0"},
     {"VTag": ["VTag569"], "X": "0"},
     {"VTag": ["VTag1131"], "X": "0"},
     {"VTag": ["VTag1693"], "X": "0"},
     {"VTag": ["VTag2255"], "X": "0"},
     {"VTag": ["VTag2817"], "X": "0"},
     {"VTag": ["VTag3379"], "X": "0"},
     {"VTag": ["VTag3941"], "X": "0"},
     {"VTag": ["VTag4503"], "X": "0"},
     {"VTag": ["VTag5065"], "X": "1"},
     {"VTag": ["VTag5627"], "X": "1"},
     {"VTag": ["VTag6189"], "X": "1"}]}

For a regular MIP problem, the JSON solution string may look like

{ "SolutionInfo": {
     "Status": 2,
     "Runtime": "2.4669170379638672e-03",
     "ObjVal": "3124",
     "ObjBound": "3124",
     "ObjBoundC": "3124",
     "MIPGap": "0",
     "IntVio": "1.958742e-08",
     "BoundVio": "0",
     "ConstrVio": "1.002e-07",
     "IterCount": "465",
     "BarIterCount": 0,
     "NodeCount": "1",
     "SolCount": 4,
     "PoolObjBound": "3124",
     "PoolObjVal": [ "3124", "3124", "3124", "3124"]},
  "Vars": [
     {"VTag": ["VTag7"], "X": "1", "Xn": [ "1", "1", "1", "1"]},
     {"VTag": ["VTag466"], "X": "0", "Xn": [ "0", "1", "1", "0"]},
     {"VTag": ["VTag925"], "X": "0", "Xn": [ "0", "0", "0", "0"]},
     {"VTag": ["VTag1384"], "X": "0", "Xn": [ "0", "0", "1", "1"]},
     {"VTag": ["VTag1843"], "X": "0", "Xn": [ "0", "1", "0", "0"]},
     {"VTag": ["VTag2302"], "X": "0", "Xn": [ "0", "1", "1", "0"]}]}

For a multi-objective MIP, the JSON solution string may look like

{ "SolutionInfo": {
     "Status": 2,
     "Runtime": "3.5403838157653809e+00",
     "ObjNVal": [ "2763", "704"],
     "IterCount": "595",
     "BarIterCount": 0,
     "NodeCount": "1",
     "SolCount": 6,
     "PoolObjVal": [ [ "2763", "704" ], [ "2763", "705" ],
                     [ "2763", "716" ], [ "2763", "718" ],
                     [ "2763", "769" ], [ "2763", "1060" ]]},
  "Vars": [
     {"VTag": ["VTag7"], "X": "1", "Xn": [ "1", "1", "1", "1", "1", "1"]},
     {"VTag": ["VTag466"], "X": "0", "Xn": [ "0", "1", "0", "0", "0", "0"]},
     {"VTag": ["VTag925"], "X": "0", "Xn": [ "0", "0", "0", "0", "1", "1"]},
     {"VTag": ["VTag1384"], "X": "0", "Xn": [ "0", "0", "0", "0", "0", "0"]},
     {"VTag": ["VTag1843"], "X": "0", "Xn": [ "0", "0", "1", "1", "0", "0"]},
     {"VTag": ["VTag2302"], "X": "0", "Xn": [ "0", "1", "0", "0", "0", "0"]}]}

For a multi-scenario model, the JSON solution string may look like

{ "SolutionInfo": {
     "Status": 2,
     "Runtime": "3.5403838157653809e+00",
     "ObjVal": "2763",
     "ObjBound": "2763",
     "ObjBoundC": "1324",
     "IntVio": "0",
     "BoundVio": "0",
     "ConstrVio": "0",
     "ScenNObjVal": ["2763", "3413", "1e+100"],
     "ScenNObjBound": ["2763", "3413", "1e+100"],
     "IterCount": "595",
     "BarIterCount": 0,
     "NodeCount": "1",
     "SolCount": 3,
     "PoolObjBound": "2763",
     "PoolObjVal": [ "2763", "2763", "2763"]},
  "Vars": [
     {"VTag": ["VTag7"], "X": "1", "ScenNX": ["1", "0", "1e+101"], "Xn": [ "1", "0", "1"]},
     {"VTag": ["VTag466"], "X": "0", "ScenNX": ["1", "1", "1e+101"], "Xn": [ "1", "1", "1"]},
     {"VTag": ["VTag925"], "X": "0", "ScenNX": ["0", "0", "1e+101"], "Xn": [ "0", "0", "0"]},
     {"VTag": ["VTag1384"], "X": "0", "ScenNX": ["2", "1", "1e+101"], "Xn": [ "2", "1", "0"]},
     {"VTag": ["VTag1843"], "X": "0", "ScenNX": ["0", "2", "1e+101"], "Xn": [ "0", "2", "1"]},
     {"VTag": ["VTag2302"], "X": "0", "ScenNX": ["0", "1", "1e+101"], "Xn": [ "0", "1", "0"]}]}
If the scenario objective value ScenNObjVal is infinite (GRB_INFINITY = 1e+100 for minimization, -GRB_INFINITY = -1e+100 for maximization), then no feasible solution has been found for this scenario. The corresponding ScenNX value for each variable will be GRB_UNDEFINED = 1e+101. Moreover, if the ScenNObjBound value for the scenario is also infinite, it means that the scenario has been proven to be infeasible.