# Gurobi

Gurobi is an industry-leading solver for mathematical optimization.

## Solvers

Model | Solvers |
---|---|

Quadratic Unconstrained Binary Optimization (QUBO) | `gurobi.qubo` |

Mathematical Programming System (MPS) | `gurobi.mps` |

Linear Programming (LP) | `gurobi.lp` |

## QUBO

`from strangeworks_optimization import StrangeworksOptimizer`

from strangeworks_optimization_models.parameter_models import GurobiParameterModel

from dimod import BinaryQuadraticModel

linear = {1: -2, 2: -2, 3: -3, 4: -3, 5: -2}

quadratic = {(1, 2): 2, (1, 3): 2, (2, 4): 2, (3, 4): 2, (3, 5): 2, (4, 5): 2}

model = BinaryQuadraticModel(linear, quadratic, "BINARY")

solver = "gurobi.qubo"

options = GurobiParameterModel(TimeLimit=60)

so = StrangeworksOptimizer(model=model, solver=solver, options=options)

sw_job = so.run()

print(f"Job slug: {sw_job.slug}")

print(f"Job status: {so.status(sw_job.slug)}")

results = so.results(sw_job.slug)

## MPS

`from strangeworks_optimization import StrangeworksOptimizer`

from strangeworks_optimization_models.problem_models import MPSFile

from strangeworks_optimization_models.parameter_models import GurobiParameterModel

model = MPSFile.read_file("example.mps")

solver = "gurobi.mps"

options = GurobiParameterModel(TimeLimit=60)

so = StrangeworksOptimizer(model=model, solver=solver, options=options)

sw_job = so.run()

print(f"Job slug: {sw_job.slug}")

print(f"Job status: {so.status(sw_job.slug)}")

results = so.results(sw_job.slug)

### Presolve

The aim of presolving is to reduce the problem size, improve numerical stability, and enhance the overall efficiency of the solver.

On Gurobi presolving takes place by default when solving MPS problems with `gurobi.mps`

. It is possible to presolve first separately using the `gurobi.presolve`

solver.

To see the full list of presolve parameters, refer to the GurobiParameterModel section.

`from strangeworks_optimization import StrangeworksOptimizer`

from strangeworks_optimization_models.parameter_models import GurobiParameterModel

from strangeworks_optimization_models.problem_models import MPSFile

so = StrangeworksOptimizer(

model = MPSFile.read_file("example.mps"),

solver = "gurobi.presolve",

options = GurobiParameterModel(Presolve=2),

)

sw_job = so.run()

presolved_model = so.results(sw_job.slug)

The returned presolved model is a remote file and can be submitted directly to `gurobi.mps`

for solving.

`so = StrangeworksOptimizer(`

model = presolved_model,

solver = "gurobi.mps",

options = GurobiParameterModel(TimeLimit=60)

)

sw_job = so.run()

results = so.results(sw_job.slug)

## Gurobi Model

Gurobi model object can be submitted to the Gurobi MPS solver by first using the `Model.write()`

method.

`import strangeworks as sw`

import gurobipy as gp

from gurobipy import GRB

import numpy as np

import tempfile

sw.authenticate(api_key)

Q = [[-1, 2, 0], [0, -1, 2], [0, 0, -1]]

num_vars = np.shape(Q)[0]

Qnew = {}

for i in range(num_vars):

for j in range(num_vars):

Qnew[(i, j)] = Q[i][j]

Q = Qnew

m = gp.Model("lat")

m.setParam("OutputFlag", True)

# Collect the variables and construct the objective function (the qubo)

vs = [m.addVar(name=str(i), vtype=GRB.BINARY) for i in range(num_vars)]

obj = gp.QuadExpr()

for i in range(num_vars):

for j in range(num_vars):

if Q[i, j] != 0:

obj += Q[i, j] * vs[i] * vs[j]

# Run optimizer and get solutions

m.setObjective(obj, GRB.MINIMIZE)

with tempfile.NamedTemporaryFile(suffix=".mps") as temp_file:

file_path = temp_file.name

m.write(file_path)

sw_model = MPSFile.read_file(file_path)

so = StrangeworksOptimizer(model=sw_model, solver="gurobi.mps")

job = so.run()

results = so.results(job.slug)

print(results.solution)

## Linear Programming

`from strangeworks_optimization import StrangeworksOptimizer`

from strangeworks_optimization_models.parameter_models import GurobiParameterModel

from strangeworks_optimization_models.problem_models import LpFile

model = LpFile.read_file("example.lp")

options = GurobiParameterModel(TimeLimit=60)

so = StrangeworksOptimizer(model=model, solver="gurobi.lp", options=options)

sw_job = so.run()

results = so.results(sw_job.slug)

## Parameters

`from strangeworks_optimization_models.parameter_models import GurobiParameterModel`

options = GurobiParameterModel(

.....

)

Below are some of the parameter types that can be used to control the behavior of the Gurobi solver. For a full list of parameters, please refer to the Gurobi documentation.

### Termination

These parameters control the conditions under which the solver will terminate.

Name | Description | Type | Default | Values (Range) |
---|---|---|---|---|

BarIterLimit | Limits the number of iterations the barrier algorithm will perform. | int | 1000 | [0, MAXINT] |

BestBdStop | Stops optimization once the best objective bound is at least this good. | double | Infinity | [-Infinity, Infinity] |

BestObjStop | Stops optimization once a solution with an objective value this good is found. | double | -Infinity | [-Infinity, Infinity] |

Cutoff | Sets a threshold objective value; optimization stops if no better value is possible. | double | Infinity for minimization, -Infinity for maximization | [-Infinity, Infinity] |

IterationLimit | Restricts the number of simplex iterations to prevent excessive computation. | int | Infinity | [0, Infinity] |

MemLimit | Sets the maximum amount of memory the solver may use, in GB. | double | None | [0, Infinity] |

NodeLimit | Imposes a limit on the number of MIP nodes explored in the search tree. | int | None | [0, Infinity] |

SoftMemLimit | Sets a soft limit on the memory usage, allowing for minimal overages. | double | None | [0, Infinity] |

SolutionLimit | Stops optimization after finding a specified number of feasible solutions. | int | None | [1, MAXINT] |

TimeLimit | Specifies the maximum time (in seconds) the solver should run. | double | None | [0, Infinity] |

WorkLimit | Limits the amount of "work" (an abstract measure of effort) the solver can perform. | int | None | [0, Infinity] |

### Tolerances

These parameters control the feasibility and optimality tolerances. The feasibility tolerance is the maximum amount by which a constraint can be violated, and the optimality tolerance is the maximum amount by which the objective function can be improved.

Name | Description | Type | Default | Values (Range) |
---|---|---|---|---|

BarConvTol | Tolerance used by the barrier algorithm to determine convergence. | float | 1e-8 | [0.0, 1.0] |

BarQCPConvTol | Tolerance for convergence when solving Quadratically Constrained Programs using the barrier method. | float | 1e-6 | [0.0, 1.0] |

FeasibilityTol | Tolerance for primal feasibility in the optimization. | float | 1e-6 | [1e-9, 1e-2] |

IntFeasTol | Tolerance to determine if an integer variable is at its bound. | float | 1e-5 | [1e-9, 1e-1] |

MarkowitzTol | Controls the threshold for numerical pivoting in the simplex algorithms. | float | 0.0078125 | [1e-4, 0.999] |

MIPGap | Relative gap between the lower and upper bounds for terminating MIP optimization. | float | 1e-4 | [0.0, Infinity] |

MIPGapAbs | Absolute gap between the lower and upper bounds for terminating MIP optimization. | float | 1e-10 | [0.0, Infinity] |

OptimalityTol | Tolerance for dual feasibility in the optimization. | float | 1e-6 | [1e-9, 1e-2] |

PSDTol | Tolerance used to check the positive semi-definiteness in optimization. | float | 1e-6 | [0, Infinity] |

### Presolve

Presolve is the process of simplifying MPS problems before solving.

Problems are presolved by default when submitted to `gurobi.mps`

but it is possible to presolve first separately using the `gurobi.presolve`

solver.

In either case, these parameters control the presolve phase of the optimization.

Name | Description | Type | Default | Values (Range) |
---|---|---|---|---|

AggFill | Specifies the level of fill allowed during presolve aggregation. | int | -1 | [-1, MAXINT] |

Aggregate | Controls the aggregation level in presolve: off, moderate, or aggressive. | bool | 1 | [0, 2] |

DualReductions | Enables or disables dual reductions during presolve. | bool | 1 | [0, 1] |

PreCrush | Allows translation of user constraints into equivalent presolved model constraints. | bool | 0 | [0, 1] |

PreDepRow | Enables or disables dependent row reduction in presolve. | bool | 1 | [0, 1] |

PreDual | Determines whether to dualize the problem during presolve. | bool | 0 | [0, 1] |

PreMIQCPForm | Specifies the form of the presolved Mixed Integer Quadratically Constrained Program (MIQCP). | int | 0 | [0, 1] |

PrePasses | Sets the maximum number of presolve passes. | int | -1 | [-1, MAXINT] |

PreQLinearize | Determines whether to linearize the quadratic terms in objective and constraints during presolve. | bool | 0 | [0, 1] |

Presolve | Sets the presolve level to control the aggressiveness of the presolve process. | int | -1 | [-1, 2] |

PreSOS1BigM | Specifies the largest coefficient allowed in SOS1 (Special Ordered Sets type 1) reformulations. | float | 1e6 | [0, Infinity] |

PreSOS1Encoding | Controls the encoding method used for SOS1 reformulations. | int | -1 | [-1, 2] |

PreSOS2BigM | Specifies the largest coefficient allowed in SOS2 (Special Ordered Sets type 2) reformulations. | float | 1e6 | [0, Infinity] |

PreSOS2Encoding | Controls the encoding method used for SOS2 reformulations. | int | -1 | [-1, 2] |

PreSparsify | Enables or disables the sparsification of the problem during presolve to reduce size without altering the optimal solution significantly. | bool | 0 | [0, 1] |