Quick Start Guide¶
Introduction¶
The Model Scaling module can be used to scale the coefficient matrix of a Gurobi model to improve numerical conditioning prior to solving. Poorly scaled models (those with large differences in coefficient magnitudes across rows or columns) can cause numerical instability in the solver, leading to inaccurate solutions or convergence issues.
The module works by computing diagonal row and column scaling matrices
\(D_r\) and \(D_c\) such that the transformed constraint matrix
\(\hat{A} = D_r A D_c\) has improved coefficient ranges. The resulting
scaled model is returned as a ScaledModel object,
which is a subclass of gurobipy.Model and can be optimized directly. After
solving, the original (unscaled) solution can be recovered via
ScaledModel.getVarsUnscaled().
Three scaling methods are available:
equilibration: iteratively scales rows and columns to bring coefficient magnitudes to a similar range. Supports all model types: (MI)LP, (MI)QP, (MI)QCP, and (MI)QCQP. This is the recommended starting point and the only method that supports models with a quadratic objective.
geometric_mean: scales rows and columns by the reciprocal of the square root of the product of the largest and smallest absolute nonzero values in each row or column. Supports (MI)LP and (MI)QCP models (linear objective only).
arithmetic_mean: scales both rows and columns by the reciprocal of their mean absolute value. Supports (MI)LP and (MI)QCP models (linear objective only).
See the Advanced Usage Guide section for guidance on choosing between methods and controlling the scaling algorithm in detail.
Scaling a Model¶
The simplest way to use the module is to call scale_model() with a
model and a method name:
import gurobipy as gp
import gurobi_modelanalyzer as gma
m = gp.read("mymodel.mps")
m_scaled = gma.scale_model(m, method="equilibration")
m_scaled.optimize()
scale_model() returns a fully constructed
ScaledModel object. You can inspect it before
calling optimize(), for example by examining the scaling factors, checking
coefficient ranges, or inspecting variables and constraints.
The scaled model is solved in the transformed space. To retrieve the solution values in the original variable space:
for var in m_scaled.getVarsUnscaled():
print(f"{var.VarName}: unscaled = {var.Xunsc:.6e}, scaled = {var.X:.6e}")
Checking Solution Quality¶
After optimization, use ScaledModel.computeUnscVio() to compute
constraint and bound violations in the original (unscaled) variable space:
m_scaled.computeUnscVio()
print(f"Max constraint violation: {m_scaled.MaxUnscConstrVio:.2e}")
print(f"Max bound violation: {m_scaled.MaxUnscBoundVio:.2e}")
MaxUnscVio is simply the larger of the two, equivalent to
max(MaxUnscConstrVio, MaxUnscBoundVio).
Individual violations per constraint are accessible via the wrappers returned
by ScaledModel.getConstrsUnscaled():
for c in m_scaled.getConstrsUnscaled():
if c.UnscViolation > 1e-6:
print(f"{c.ConstrName}: violation = {c.UnscViolation:.2e}")