API Examples

Suboptimal solutions

Given a solution, we can use the SolCheck.test_sol() function to test it.

import gurobipy as gp
import gurobi_modelanalyzer as gma

m = gp.read("afiro.mps")

sol = {m.getVarByName("X01"): 78, m.getVarByName("X22"): 495}
sc = gma.SolCheck(m)

sc.test_sol(sol)
print(f"Solution Status: {sc.Status}")

Will print:

Read MPS format model from file afiro.mps
Reading time = 0.00 seconds
AFIRO: 27 rows, 32 columns, 83 nonzeros
Gurobi Optimizer version 11.0.3 build v11.0.3rc0

Thread count: 8 physical cores, 8 logical processors, using up to 8 threads

Optimize a model with 27 rows, 32 columns and 83 nonzeros
Model fingerprint: 0x540c3b7f
Coefficient statistics:
  Matrix range     [1e-01, 2e+00]
  Objective range  [3e-01, 1e+01]
  Bounds range     [8e+01, 5e+02]
  RHS range        [4e+01, 5e+02]
Presolve removed 19 rows and 22 columns
Presolve time: 0.03s
Presolved: 8 rows, 10 columns, 27 nonzeros

Iteration    Objective       Primal Inf.    Dual Inf.      Time
       0   -4.5969189e+02   2.146875e+00   0.000000e+00      0s
       3   -4.5969189e+02   0.000000e+00   0.000000e+00      0s

Solved in 3 iterations and 0.05 seconds (0.00 work units)
Optimal objective -4.596918857e+02

Solution is feasible for feasibility tolerance of 1e-06

Solution Status: 13

We can check this solution against the optimal one by calling SolCheck.optimize().

sc.optimize()
for v in sol.keys():
    print(f"{v.VarName}: Fixed value: {sol[v]}, Computed value: {v.X}")

Produces

Comparing quality with original solution

Gurobi Optimizer version 11.0.3 build v11.0.3rc0

Thread count: 8 physical cores, 8 logical processors, using up to 8 threads

Optimize a model with 27 rows, 32 columns and 83 nonzeros
Coefficient statistics:
  Matrix range     [1e-01, 2e+00]
  Objective range  [3e-01, 1e+01]
  Bounds range     [0e+00, 0e+00]
  RHS range        [4e+01, 5e+02]

Iteration    Objective       Primal Inf.    Dual Inf.      Time
       0   -3.1277714e+30   1.240950e+31   3.127771e+00      0s
       4   -4.6475314e+02   0.000000e+00   0.000000e+00      0s

Solved in 4 iterations and 0.00 seconds (0.00 work units)
Optimal objective -4.647531429e+02

Objectives:
Fixed:      -459.6919
Optimal:    -464.7531
Difference: -5.0613

X01: Fixed value: 78, Computed value: 80.0
X22: Fixed value: 495, Computed value: 500.0

We can see that the solution we provided is worse than the optimal solution by -5.0613 in total, and the difference in the solution values that we provided.

Test an infeasible solution

m = gp.read("misc07.mps")
sol = {m.getVarByName("COL260"): 2400.5}
sc = gma.SolCheck(m)

sc.test_sol(sol)

print(f"Solution Status: {sc.Status}")

Will print:

Read MPS format model from file misc07.mps
Reading time = 0.00 seconds
MISC07: 212 rows, 260 columns, 8619 nonzeros
Gurobi Optimizer version 11.0.3 build v11.0.3rc0

Thread count: 8 physical cores, 8 logical processors, using up to 8 threads

Optimize a model with 212 rows, 260 columns and 8619 nonzeros
Model fingerprint: 0xd79ad074
Variable types: 1 continuous, 259 integer (0 binary)
Coefficient statistics:
  Matrix range     [1e+00, 7e+02]
  Objective range  [1e+00, 1e+00]
  Bounds range     [1e+00, 2e+03]
  RHS range        [1e+00, 3e+02]
Presolve removed 0 rows and 7 columns
Presolve time: 0.00s

Explored 0 nodes (0 simplex iterations) in 1.72 seconds (0.00 work units)
Thread count was 1 (of 8 available processors)

Solution count 0

Model is infeasible
Best objective -, best bound -, gap -

Solution is infeasible for feasibility tolerance of 1e-06

Solution Status: 3

Here we can see that the solution we provided makes the problem infeasible. We can use the SolCheck.inf_repair() function to repair the infeasibility.

sc.inf_repair()
for c in m.getConstrs():
    if abs(c._Violation) > 0.0001:
        print(f"{c.ConstrName}: RHS: {c.RHS}, Violation: {c._Violation}")

We get:

Relaxing to find smallest violation from fixed solution

Gurobi Optimizer version 11.0.3 build v11.0.3rc0

Thread count: 8 physical cores, 8 logical processors, using up to 8 threads

Optimize a model with 212 rows, 507 columns and 8866 nonzeros
Model fingerprint: 0x396303c6
Variable types: 248 continuous, 259 integer (0 binary)
Coefficient statistics:
  Matrix range     [1e+00, 7e+02]
  Objective range  [1e+00, 1e+00]
  Bounds range     [1e+00, 2e+03]
  RHS range        [1e+00, 3e+02]
Found heuristic solution: objective 2534.5000000
Presolve removed 0 rows and 7 columns
Presolve time: 0.01s
Presolved: 212 rows, 500 columns, 8823 nonzeros
Variable types: 70 continuous, 430 integer (380 binary)

Root relaxation: objective 0.000000e+00, 124 iterations, 0.00 seconds (0.00 work units)

    Nodes    |    Current Node    |     Objective Bounds      |     Work
 Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time

     0     0    0.00000    0   22 2534.50000    0.00000   100%     -    0s
H    0     0                     207.5000000    0.00000   100%     -    0s
H    0     0                     173.5000000    0.00000   100%     -    0s
H    0     0                     110.5000000    0.00000   100%     -    0s
H    0     0                      97.5000000    0.00000   100%     -    0s
H    0     0                      61.5000000    0.00000   100%     -    0s
H    0     0                      12.5000000    0.00000   100%     -    0s
     0     0    0.50000    0   25   12.50000    0.50000  96.0%     -    0s
H    0     0                       7.5000000    0.50000  93.3%     -    0s
H    0     0                       6.5000000    0.50000  92.3%     -    0s
     0     0    0.50000    0   34    6.50000    0.50000  92.3%     -    0s
     0     0    0.50000    0   31    6.50000    0.50000  92.3%     -    0s
     0     0    0.50000    0   30    6.50000    0.50000  92.3%     -    0s
     0     0    0.50000    0   27    6.50000    0.50000  92.3%     -    0s
     0     0    0.50000    0   23    6.50000    0.50000  92.3%     -    0s
     0     0    0.50000    0   27    6.50000    0.50000  92.3%     -    0s
     0     0    0.50000    0   22    6.50000    0.50000  92.3%     -    0s
H    0     0                       5.5000000    0.50000  90.9%     -    0s
     0     2    0.50000    0   22    5.50000    0.50000  90.9%     -    0s
H   80    88                       4.5000000    0.50000  88.9%  41.2    0s
H  132   209                       3.5000000    0.50000  85.7%  37.7    0s
*  706   534              39       2.5000000    0.50000  80.0%  24.9    0s
H 1487   801                       2.5000000    0.50000  80.0%  25.0    1s
H 1490   801                       2.5000000    0.50000  80.0%  25.0    1s
  5201  1713    0.58621   24   19    2.50000    0.50000  80.0%  24.9    5s
* 6181   908              26       1.5000000    0.50000  66.7%  24.6    5s

Cutting planes:
  Gomory: 4
  MIR: 8
  Flow cover: 65

Explored 9399 nodes (234850 simplex iterations) in 6.19 seconds (6.17 work units)
Thread count was 8 (of 8 available processors)

Solution count 10: 1.5 2.5 2.5 ... 61.5

Optimal solution found (tolerance 1.00e-04)
Best objective 1.500000000000e+00, best bound 1.500000000000e+00, gap 0.0000%

Fixed values are 1.5 from a feasible solution

ROW001: RHS: 0.0, Violation: -0.5
ROW074: RHS: 1.0, Violation: 1.0

From this we can see that we would have to relax constraints ROW001 and ROW074 by -0.5 and 1.0 to make the problem feasible.