Try our new documentation site (beta).
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. By default the JSON solution will contain only model attributes and variable data. Users can tag variables (using the VTag attribute), linear constraints (using the CTag attribute), and quadratic constraints (using the QCTag attribute) to request data on a more selective basis. If any such attribute is used, 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 element is tagged, for example, then the
Vars
array will be
present and contain names and solution values for all variables with
non-zero solution values. 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 variables. If no explicit tags (VTag,
CTag, or QCTag) have been set at all, all variables will be included,
along with their names. Otherwise only variables wih a set VTag will
be included, and this tag will be part of the object. Some data will
always be present, while other data will depend on the problem type or
the results of the optimization. This component may include the
following variable attributes:
- VarName
- The variable's name in the model. Present only if no tags have been set.
- VTag
- 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 corresponding to the VarName or VTag in the current solution.
Note objects with a zero variable value will be omitted from the Vars
array unless
JSONSolDetail
is greater than zero. - 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.
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.
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.