Solution File Formats#

SOL format#

A Gurobi solution (SOL) file is used to output a solution vector. It can be written (using GRBwrite, for example) whenever a solution is available.

The file consists of variable-value pairs, each on its own line. The file contains one line for each variable in the model. The following is a simple example:

# Solution file
x  1.0
y  0.5
z  0.2

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 with a non-zero objective value 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. 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.

MST format#

A MIP start (MST) file is used to specify an initial solution for a mixed integer programming model. The file lists values to assign to the variables in the model. If a MIP start has been imported into a MIP model before optimization begins (using GRBread, for example), the Gurobi optimizer will attempt to build a feasible solution from the specified start values. A good initial solution often speeds the solution of the MIP model, since it provides an early bound on the optimal value, and also since the specified solution can be used to seed the local search heuristics employed by the MIP solver.

A MIP start file consists of variable-value pairs, each on its own line. Any line that begins with the hash sign (#) is a comment line and is ignored. The following is a simple example:

# MIP start
x1  1
x2  0
x3  1

Importing a MIP start into a model is equivalent to setting the Start attribute for each listed variable to the associated value. If the same variable appears more than once in a start file, the last assignment is used. Importing multiple start files is equivalent to reading the concatenation of the imported files.

Note that start files don’t need to specify values for all variables. When variable values are left unspecified, the Gurobi solver will try to extend the specified values into a feasible solution for the full model.

It is important to mention that when saving an MST file, Gurobi will not save the values of continuous variables. If you want to save a complete description of the best solution found, we recommend to save it as a solution file (SOL format). This will guarantee that you will save the values for each variable present in your model.

BAS format#

An LP basis (BAS) file is used to specify an initial basis for a continuous model. The file provides basis status information for each variable and constraint in the model. If written by Gurobi, to reduce the size of the file, it only includes the difference to the slack basis. In a slack basis for each row the corresponding slack variable is basic while all other problem variables are at their lower bound. If a basis has been imported into a continuous model before optimization begins (using GRBread, for example), and if a simplex optimizer has been selected (through the Method parameter), the Gurobi simplex optimizer begins from the specified basis.

A BAS file begins with a NAME line, and ends with an ENDATA statement. No information is retrieved from these lines, but they are required by the format. Between these two lines are basis status lines, each consisting of two or three fields and starting with a white space character. If the first field is LL, UL, or BS, the variable named (slack variables are not allowed) in the second field is non-basic at its lower bound, non-basic at its upper bound, or basic, respectively. Any additional fields are ignored. If the first field is XL or XU, the variable named in the second field is basic, while the row named in the third field states that the corresponding slack variable is non-basic at its lower or upper bound, respectively.

The following is a simple example:

NAME  example.bas
 XL x1 c1
 XU x2 c2
 UL x3
 LL x4
ENDATA

Importing a basis into a model is equivalent to setting the VBasis and CBasis attributes for each listed variable and constraint to the specified basis status.

A near-optimal basis can speed the solution of a difficult LP model. However, specifying a start basis that is not extremely close to an optimal solution will often slow down the solution process. Exercise caution when providing start bases.