Gurobi Summit Amsterdam
From \[B(x+\delta x) = b + \delta b \rightarrow \delta x= B^{-1}\delta b\] Cauchy-Schwartz inequalities: \[\|\delta x\| \leq \| B^{-1}\|\|\delta b\|, \|b\| \leq \| B\|\|x\|\] Combine: \[\frac{\|\delta x\|}{\|x\|} \leq \underbrace{\| B\|\| B^{-1}\|}_{\kappa}\frac{\|\delta b\|}{\|b\|}\]
Definition of condition number \(\kappa\) of a square matrix \(B\) for solving \(Bx=b\)
\(\kappa(B) = \|B\|\cdot\|B^{-1}\|\) provides upper bound on input error amplification in the solution of a linear system \(Bx=b\). It is the normed reciprocal of the distance to singularity.
\[ \frac{\|\delta x\|}{\|x\|} \leq \kappa(B) \cdot \frac{\|\delta b\|}{\|b\|} \]
Double precision
Default feasibility tolerance
\(\kappa\) :
\(\;1 \dots 10^7\)
stable
\(\;10^7 \dots 10^{10}\)
suspicious
\(\;10^{10} \dots 10^{14}\)
unstable
\(\;>10^{14}\)
ill-posed
Note
Condition number always represents an upper bound or worst-case scenario!
Linear Algebra Interpretation
Geometrical interpretation
The condition number is the ratio between two circles: the smallest circle enclosing the feasible region and the largest circle enclosed by the feasible region
Which system of equations do you think will have a better condition number?
A:
B:
\[
\begin{align}
& B=\begin{pmatrix}
M & 1\\
0 & \frac{1}{M} \end{pmatrix}
\text{ has inverse }
B^{-1}=\begin{pmatrix}
\frac{1}{M} & -1\\
0 & M \end{pmatrix}\\
& \Rightarrow \|B\| \geq M \text{ and } \|B^{-1}\| \geq M\\
& \Rightarrow \kappa(B) = \|B\|\cdot\|B^{-1}\| \color{red}{\geq M^2}
\end{align}
\]
big M
valuesWhat would happen if we replace \(\frac{1}{M}\) with just \(M\)?
\[ \begin{align} & B=\begin{pmatrix} M & 1\\ 0 & M \end{pmatrix} \text{ has inverse } B^{-1}=? \end{align} \]
The inverse would become: \[ B^{-1}=\begin{pmatrix} \frac{1}{M} & \frac{-1}{M^2}\\ 0 & \frac{1}{M} \end{pmatrix}\Rightarrow \|B^{-1}\|\geq \frac{1}{M} \Rightarrow \kappa(B) \geq 1 \]
c306: 0.416666667 x80 – 100 x90 = 0 [...] c11360: 0.416666666 x80 – 100 x90 = 0
Reasons for a high condition number
How can we fix this?
Important
The condition number is a property of the problem! Not the solution process.
Probably reformulation but wait and see!
A solution to an LP requires:
Requires solving two linear systems of equations (with basis matrix \(B\)):
In the simplex algorithm, large condition numbers may lead to:
For verification, \(B\) is used.
Fails basic mathematical properties:
Fails others: Commutativity in multiplication
type | # of bits | mantissa | exponent | arch |
---|---|---|---|---|
float |
32 | 23 | 8 | most |
double |
64 | 52 | 11 | most |
long double |
80 | 63 | 15 | e.g. x86-64 (intel or AMD) |
long double |
128 | 112 | 15 | e.g. Power 9 |
float
representation of 1234.5 (calculator)
model.printStats()
model.printQuality()
Warning
Look out for warnings!
Prior to optimization 🚩
Optimize a model with 306204 rows, 579547 columns and 1563587 nonzeros
Model fingerprint: 0x21cdd0c7
Coefficient statistics:
Matrix range [1e-05, 2e+08]
Objective range [8e-370, 1e+05]
Bounds range [1e-03, 3e+09]
RHS range [5e-01, 2e+04]
Warning: Model contains large matrix coefficient range
Warning: Model contains large bounds
Consider reformulating model or setting NumericFocus
parameter to avoid numerical issues.
During LP solving (simplex or barrier) 2x🚩
Iteration Objective Primal Inf. Dual Inf. Time
[...]
56658 -3.3179831e+03 4.239720e+05 0.000000e+00 20s
Warning: Markowitz tolerance tightened to 0.0625
67557 -3.2801023e+03 1.974011e+04 0.000000e+00 25s 69517 3.7944349e+02 6.207667e+04 0.000000e+00 30s
Warning: 1 variables dropped from basis
Warning: switch to quad precision
78320 1.7027054e+08 1.149199e+04 0.000000e+00 35s
During the MIP node process 🚩
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
[...]
3252 0 278173.332 0 2120 275179.027 277183.668 0.73% 211 401s
3253 0 278173.020 0 2060 275179.027 277115.904 0.70% 211 405s
Relaxation Markowitz Tolerance tightened to 0.5
3254 0 278173.020 0 2060 275179.027 277115.904 0.70% 211 406s
[...]
3575 295 postponed 43 275179.027 277115.904 0.70% 321 461s
3599 314 infeasible 44 275179.027 277115.904 0.70% 332 467s
3673 391 276640.457 55 1881 275179.027 277115.904 0.70% 328 471s
postponed
nodes may have to be processed later - but hopefully never. Many of these in quick succession is 3x🚩
Post Optimization 3x🚩
Solved in 131511 iterations and 75.99 seconds (66.11 work units)
Optimal objective 1.730551793e+08
Warning: unscaled dual violation = 0.0141201 and residual = 0.0111682
MaxVio
. Checkout other Quality Attributes.Important
Numerical issues can lead to different solutions!
harp2
(using MIPGap=0
).import gurobipy as gp
M = 1e10
opts = {"OutputFlag": 0}
with gp.Env(params=opts) as env, gp.Model(env=env) as m:
c = m.addVar(name="c", lb=0)
b = m.addVar(name="b", vtype=gp.GRB.BINARY)
# Fix variables
c.UB = 1e4
c.LB = 1e4
b.UB = 1e-6 # This is technically zero based on the IntFeasTol
b.LB = 1e-6
m.addConstr(c <= M*b) # So we really want c = 0 since b = 0
m.optimize()
print(f"Is the model optimal? {m.Status==gp.GRB.OPTIMAL}")
Is the model optimal? True
How can we fix this?
import gurobipy as gp
M = 1e10
opts = {"OutputFlag": 0}
with gp.Env(params=opts) as env, gp.Model(env=env) as m:
c = m.addVar(name="c", lb=0)
b = m.addVar(name="b", vtype=gp.GRB.BINARY)
# Fix variables
c.UB = 1e4
c.LB = 1e4
b.UB = 1e-6 # This is technically zero based on the IntFeasTol
b.LB = 1e-6
m.addConstr((b == 0) >> (c == 0))
m.optimize()
print(f"Is the model optimal? {m.Status==gp.GRB.OPTIMAL}")
Is the model optimal? False
import gurobipy as gp
M = 1e10
opts = {"OutputFlag": 0, "IntFeasTol": 1e-7}
with gp.Env(params=opts) as env, gp.Model(env=env) as m:
c = m.addVar(name="c", lb=0)
b = m.addVar(name="b", vtype=gp.GRB.BINARY)
# Fix variables
c.UB = 1e4
c.LB = 1e4
b.UB = 1e-6 # This is technically zero based on the IntFeasTol
b.LB = 1e-6
m.addConstr(c <= M*b) # So we really want c = 0 since b = 0
m.optimize()
print(f"Is the model optimal? {m.Status==gp.GRB.OPTIMAL}")
Is the model optimal? False
… and choosing the right ones is no easy task
NumericFocus = [0, 1, 2, 3]
Meta parameter that affects many aspects of the solution process:
Presolve
Root relaxation
Cuts
>= 2
= 3
Presolve = [-1, 0, 1, 2]
Presolve typically makes numerically challenging models worse.
The main culprits are:
Aggregate
- may introduce accumulation of numerical errors
0
to deactivate aggregationRemember the warning:
Iteration Objective Primal Inf. Dual Inf. Time
[....]
56658 -3.3179831e+03 4.239720e+05 0.000000e+00 20s
Warning: Markowitz tolerance tightened to 0.0625
[....]
Try setting it to the displayed value right from the start!
Quad = [-1, 0, 1]
-1
switches dynamically to quadruple precision if numerical issues ariseBarHomogeneous = [-1, 0, 1]
Crossover = [-1, ..., 4]
0
) if it stalls, or even setting Quad
to 1
this can help!Cuts = [-1, ..., 3]
0
: Disable all cuts (together with CutPasses = 0
to be completely shut off, may affect heuristics, so I do not recommend this)1
: Moderate cut generation2, 3
: Aggressive and even more aggressiveGomoryPasses
IntegralityFocus = [0, 1]
General constraints are reformulated to a mix of linear and SOS1/2 constraints (SOS2 are only used for PWL approximations).
PreSOS1BigM = 0
to turn off the linearisation (which uses Big-M values) and use them in branching.
PreMIQCPForm = [0, 1, 2]
set to 0 to turn off any reformulation and handle them in brancem in branchingg
FuncNonlinear = [0, 1]
FuncPieces
, FuncPieceError
, FuncPieceLength
, FuncPieceRatio
are obsoleteAnalyze:
Warning
Don’t ignore the warnings!
Model instance:
Mathematical formulation:
Warning
Turn to parameter tuning only after model improvements have been investigated!
Tip
Contact the Gurobi Experts team for assistance!
FeasRelax
Modified model minimizing the amount by which the bounds and linear constraints of the original model are violated
Violation can be measured as:
Infeasible model
\[ \begin{align*} \min &~c^T x \\ \text{s. t. } &~Ax \leq b \\ &~x \geq 0 \end{align*} \]
Feasibility relaxation
\[ \begin{align*} \min &||(s, u)||_p \\ \text{s. t. } &~Ax -s \leq b \\ &~x + u \geq 0 \\ &~s, u \geq 0 \end{align*} \]
Tip
Also very helpful to investigate why a model is infeasible!
Apply FeasRelax
to minimize the sum of infeasibilities of:
\[ \begin{align} B^Ty = 0 \\ e^Ty = 1 \\ y \; \text{free} \end{align} \]
\[ \begin{align} By = 0 \\ e^Ty = 1 \\ y \; \text{free} \end{align} \]
Third case: Examine angles of pairs of matrix rows and columns
NumericFocus=3
and ScaleFlag=2
if row and column ratios are largePRM
filepython -m pip install gurobi-modelanalyzer
Basic usage:
Modified afiro
instance for demonstration:
afiro
kappa_explain()
will generate a new LP or MPS file, containing the ill-conditioning certificate:afiro_kappaexplain.lp
:Minimize
0 X36 + 0 X04 + 0 X15 + 0 X16 + 0 X26 + 0 X38 + 0 X37
Subject To
GRB_Combined_Row: 0.0303868836044176 X23 + 4.80518e-10 X01
- 4.65661e-10 X03 = 0
(mult=2696322.968477607)R09x: - 0.9999999000000001 X01 + X03 = 0
(mult=-2696322.6896988587)R09: - X01 + X03 = 0
(mult=0.2787787486643817)X46: - X03 + 0.109 X22 <= 0
(mult=0.030386883604417606)R19: X23 - X22 + X24 + X25 = 0
(mult=0.030386883604417606)X45: - X25 <= 0
(mult=0.030386883604417606)X48: 0.301 X01 - X24 <= 0
Bounds
End
afiro
instanceangle_explain()
returns a list of tuples:
neos-1603965
(MIPLIB 2017)model.relax()
to relax integrality conditions1.60000000016e+21
(original model)angle_explain()
does not reveal any almost parallel rows or columnsSubject To
GRB_Combined_Row: = 1.000000015655
(mult=0.999999999815)R24991: C8008 - C8009 >= 0
(mult=9.9999999981499e-11)R9004: - 1e+10 C8008 <= 0
(mult=9.9999999981499e-11)R13004: - 0.15 C7002 + 1e+10 C8009 <= 1e+10
(mult=1.4999999997225e-11)R1030: C3030 - C7001 <= 0
(mult=-1.4999999997225e-11)R1966: C3966 - C7001 <= 0
(mult=-1.4999999997225e-11)R2966: C4966 - C7002 <= 0
(mult=-1.4999999997225e-11)R28014: C0030 + C3030 = 7165
(mult=1.4999999997225e-11)R28950: C0966 + C3966 + C4966 = 8221
(mult=1.12499999982e-11)R0030: 1.3333333333 C0030 = 0
(mult=-1.12499999982e-11)R0966: 1.3333333333 C0966 = 0
big-M
values of \(10^{10}\) are the issue hereTest and diagnose a solution for your model e.g.
import gurobipy as gp
import gurobi_modelanalyzer as gma
m = gp.read("glass4.mps")
sol = {m.getVarByName("x1"): 600, m.getVarByName("x22"): 0}
sc = gma.SolCheck(m)
sc.test_sol(sol)
print(f"Solution Status: {sc.Status}")
sc.optimize()
for v in sol.keys():
print(f"{v.VarName}: Fixed value: {sol[v]}, Computed value: {v.X}")
converttofractions()
:
matrix_bitmap()
:
spy()
(matplotlib
) to inspect sparsity patternTrack down reasons for numerical issues
Open-source (Apache-2.0) on GitHub:
Install via pip:
python -m pip install gurobi-modelanalyzer
Currently only supports LPs (use model.relax()
to inspect root LP of MIPs)
Get involved and share your feedback and ideas!
www.gurobi.com
©️ Gurobi Optimization