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:
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:
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:
JSONSolDetail
is greater than zero.
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:
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:
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.