sensitivity.py#
#!/usr/bin/env python3.11
# Copyright 2025, Gurobi Optimization, LLC
# A simple sensitivity analysis example which reads a MIP model from a file
# and solves it. Then uses the scenario feature to analyze the impact
# w.r.t. the objective function of each binary variable if it is set to
# 1-X, where X is its value in the optimal solution.
#
# Usage:
# sensitivity.py <model filename>
#
import sys
import gurobipy as gp
from gurobipy import GRB
# Maximum number of scenarios to be considered
maxScenarios = 100
if len(sys.argv) < 2:
print("Usage: sensitivity.py filename")
sys.exit(0)
# Read model
model = gp.read(sys.argv[1])
if model.IsMIP == 0:
print("Model is not a MIP")
sys.exit(0)
# Solve model
model.optimize()
if model.Status != GRB.OPTIMAL:
print(f"Optimization ended with status {model.Status}")
sys.exit(0)
# Store the optimal solution
origObjVal = model.ObjVal
for v in model.getVars():
v._origX = v.X
scenarios = 0
# Count number of unfixed, binary variables in model. For each we create a
# scenario.
for v in model.getVars():
if v.LB == 0.0 and v.UB == 1.0 and v.VType in (GRB.BINARY, GRB.INTEGER):
scenarios += 1
if scenarios >= maxScenarios:
break
# Set the number of scenarios in the model
model.NumScenarios = scenarios
scenarios = 0
print(f"### construct multi-scenario model with {scenarios} scenarios")
# Create a (single) scenario model by iterating through unfixed binary
# variables in the model and create for each of these variables a scenario
# by fixing the variable to 1-X, where X is its value in the computed
# optimal solution
for v in model.getVars():
if (
v.LB == 0.0
and v.UB == 1.0
and v.VType in (GRB.BINARY, GRB.INTEGER)
and scenarios < maxScenarios
):
# Set ScenarioNumber parameter to select the corresponding scenario
# for adjustments
model.Params.ScenarioNumber = scenarios
# Set variable to 1-X, where X is its value in the optimal solution
if v._origX < 0.5:
v.ScenNLB = 1.0
else:
v.ScenNUB = 0.0
scenarios += 1
else:
# Add MIP start for all other variables using the optimal solution
# of the base model
v.Start = v._origX
# Solve multi-scenario model
model.optimize()
# In case we solved the scenario model to optimality capture the
# sensitivity information
if model.Status == GRB.OPTIMAL:
modelSense = model.ModelSense
scenarios = 0
# Capture sensitivity information from each scenario
for v in model.getVars():
if v.LB == 0.0 and v.UB == 1.0 and v.VType in (GRB.BINARY, GRB.INTEGER):
# Set scenario parameter to collect the objective value of the
# corresponding scenario
model.Params.ScenarioNumber = scenarios
# Collect objective value and bound for the scenario
scenarioObjVal = model.ScenNObjVal
scenarioObjBound = model.ScenNObjBound
# Check if we found a feasible solution for this scenario
if modelSense * scenarioObjVal >= GRB.INFINITY:
# Check if the scenario is infeasible
if modelSense * scenarioObjBound >= GRB.INFINITY:
print(
f"Objective sensitivity for variable {v.VarName} is infeasible"
)
else:
print(
f"Objective sensitivity for variable {v.VarName} is unknown (no solution available)"
)
else:
# Scenario is feasible and a solution is available
print(
f"Objective sensitivity for variable {v.VarName} is {modelSense * (scenarioObjVal - origObjVal):g}"
)
scenarios += 1
if scenarios >= maxScenarios:
break