What-If Analysis Example¶
Overview¶
This example demonstrates LumiX’s what-if analysis capabilities for quick, interactive exploration of parameter changes and their impact on optimal solutions.
What-if analysis provides immediate answers to tactical questions without requiring full scenario setup - perfect for rapid decision support and operational planning.
Problem Description¶
A manufacturing company needs quick answers to tactical questions:
What if we get 200 more labor hours?
What if machine capacity is reduced by 100 hours (equipment failure)?
What if we relax minimum production requirements?
Which resources are most valuable to expand?
What is the ROI of different capacity investments?
Objective: Quickly assess impact of parameter changes on profitability.
Mathematical Foundation¶
Base Model:
What-If Modification: Change constraint RHS from \(b\) to \(b'\):
Analyze impact: \(\Delta \text{objective} = f(x^*_{new}) - f(x^*_{old})\)
Key Features¶
Constraint Modification¶
Quickly modify and resolve:
.expression(LXLinearExpression[Product]().add_term(production, 1.0))
.ge()
.rhs(lambda p: float(p.min_production))
.from_data(PRODUCTS)
.indexed_by(lambda p: p.name)
)
Key Points:
.increase_constraint_rhs()increases right-hand sideby=200adds 200 unitsReturns result object with impact analysis
Multiple Modification Types¶
Various ways to modify constraints:
# Increase by absolute amount
result = whatif.increase_constraint_rhs("capacity", by=200)
# Decrease by absolute amount
result = whatif.decrease_constraint_rhs("capacity", by=100)
# Set to specific value
result = whatif.increase_constraint_rhs("capacity", to=1500)
# Relax by percentage (make less restrictive)
result = whatif.relax_constraint("minimum", by_percent=0.5)
# Tighten by percentage (make more restrictive)
result = whatif.tighten_constraint("capacity", by_percent=0.2)
Bottleneck Discovery¶
Test all constraints to find bottlenecks:
# What-if #1: Increase labor hours
print("\n" + "-" * 80)
print("WHAT-IF #1: Increase Labor Hours by 200")
Sensitivity Range Analysis¶
Analyze objective across parameter range:
print(f"\nOriginal Profit: ${result.original_objective:,.2f}")
print(f"New Profit: ${result.new_objective:,.2f}")
print(f"Change: ${result.delta_objective:,.2f} ({result.delta_percentage:+.2f}%)")
print(f"\n⚠ Supply Risk: 20% material shortage would cost ${abs(result.delta_objective):,.2f}")
Investment Comparison¶
Compare multiple investment options:
print(f"\n► Primary Bottleneck: {resource_name}")
print(f" Marginal Value: ${top_value:.2f} per unit")
print(f" Recommendation: Prioritize expanding this resource")
if top_value > 1.0:
print(f" ✓ HIGH PRIORITY: Strong ROI from capacity expansion")
print(f" - Each unit of capacity adds ${top_value:.2f} to profit")
print(f" - Consider immediate investment if cost < ${top_value:.2f}/unit")
elif top_value > 0.1:
print(f" → MODERATE PRIORITY: Positive ROI from expansion")
else:
print(f" ✗ LOW PRIORITY: Minimal profit impact")
Running the Example¶
Prerequisites:
pip install lumix
pip install ortools # or cplex, gurobi
Run:
cd examples/10_whatif_analysis
python whatif_analysis.py
Expected Output:
====================================================================
WHAT-IF ANALYSIS: Quick Impact Assessment
====================================================================
Solving baseline model...
Baseline Profit: $12,345.67
--------------------------------------------------------------------
WHAT-IF #1: Increase Labor Hours by 200
--------------------------------------------------------------------
Original Profit: $12,345.67
New Profit: $12,845.67
Change: $500.00 (+4.05%)
Interpretation: Adding 200 labor hours increases profit by $500.00
Marginal value: $2.50 per labor hour
--------------------------------------------------------------------
WHAT-IF #2: Decrease Machine Hours by 100 (Equipment Failure)
--------------------------------------------------------------------
Original Profit: $12,345.67
New Profit: $12,220.67
Change: -$125.00 (-1.01%)
⚠ Risk Assessment: Machine failure would cost $125.00 in lost profit
====================================================================
BOTTLENECK IDENTIFICATION: Testing Resource Constraints
====================================================================
Resource Improvement Per Unit Priority
--------------------------------------------------------------------
Labor Hours $25.00 $2.50 HIGH
Machine Hours $12.50 $1.25 MEDIUM
Raw Materials $0.00 $0.00 LOW
► Primary Bottleneck: Labor Hours
Marginal Value: $2.50 per unit
Recommendation: Prioritize expanding this resource
Complete Code Walkthrough¶
Step 1: Create What-If Analyzer¶
usage_expr = LXLinearExpression().add_term(
production, coeff=lambda p, r=resource: get_resource_usage(p, r)
)
Step 2: Test Parameter Changes¶
# Constraints: Minimum production requirements
model.add_constraint(
LXConstraint[Product]("min_production")
.expression(LXLinearExpression[Product]().add_term(production, 1.0))
.ge()
.rhs(lambda p: float(p.min_production))
.from_data(PRODUCTS)
.indexed_by(lambda p: p.name)
)
return model
# ==================== WHAT-IF ANALYSIS ====================
def run_whatif_analysis():
"""Run basic what-if analysis with simple parameter changes.
This function demonstrates quick, interactive what-if analysis by testing
individual parameter changes and observing their impact on profit:
1. Get baseline solution for comparison
2. Test increasing labor hours by 200 units
3. Test decreasing machine hours by 100 units (equipment failure)
4. Test increasing raw materials by 100 units
5. Test setting labor hours to a specific value (1500)
6. Test tightening raw materials by 20% (supply chain issues)
Each test shows the profit impact, percentage change, and marginal value
per unit of resource, enabling quick ROI assessment for operational changes.
Returns:
None. Results are printed to console including:
- Baseline profit value
- New profit after each change
- Delta in objective value ($ change)
- Percentage change
Step 3: Identify Bottlenecks¶
model = build_production_model()
optimizer = LXOptimizer().use_solver(solver_to_use)
whatif = LXWhatIfAnalyzer(model, optimizer)
# Get baseline
print("\nSolving baseline model...")
baseline = whatif.get_baseline_solution()
print(f"Baseline Profit: ${baseline.objective_value:,.2f}")
# What-if #1: Increase labor hours
print("\n" + "-" * 80)
print("WHAT-IF #1: Increase Labor Hours by 200")
print("-" * 80)
result = whatif.increase_constraint_rhs("capacity_Labor Hours", by=200)
print(f"\nOriginal Profit: ${result.original_objective:,.2f}")
print(f"New Profit: ${result.new_objective:,.2f}")
print(f"Change: ${result.delta_objective:,.2f} ({result.delta_percentage:+.2f}%)")
print(f"\nInterpretation: Adding 200 labor hours would increase profit by ${result.delta_objective:,.2f}")
print(f"Marginal value: ${result.delta_objective/200:.2f} per labor hour")
# What-if #2: Decrease machine hours
print("\n" + "-" * 80)
print("WHAT-IF #2: Decrease Machine Hours by 100 (Equipment Failure)")
print("-" * 80)
result = whatif.decrease_constraint_rhs("capacity_Machine Hours", by=100)
print(f"\nOriginal Profit: ${result.original_objective:,.2f}")
print(f"New Profit: ${result.new_objective:,.2f}")
print(f"Change: ${result.delta_objective:,.2f} ({result.delta_percentage:+.2f}%)")
print(f"\n⚠ Risk Assessment: Machine failure would cost ${abs(result.delta_objective):,.2f} in lost profit")
# What-if #3: Increase raw materials
print("\n" + "-" * 80)
print("WHAT-IF #3: Increase Raw Materials by 100 Units")
print("-" * 80)
result = whatif.increase_constraint_rhs("capacity_Raw Materials", by=100)
print(f"\nOriginal Profit: ${result.original_objective:,.2f}")
print(f"New Profit: ${result.new_objective:,.2f}")
print(f"Change: ${result.delta_objective:,.2f} ({result.delta_percentage:+.2f}%)")
if result.delta_objective > 0:
print(f"\n✓ Benefit: Adding raw materials increases production capacity and profit")
print(f" Marginal value: ${result.delta_objective/100:.2f} per unit of raw material")
else:
print(f"\n✗ No benefit: Raw materials are not currently a bottleneck")
Step 4: Analyze Sensitivity Ranges¶
print("WHAT-IF #5: Tighten Raw Materials by 20% (Supply Chain Issues)")
print("-" * 80)
result = whatif.tighten_constraint("capacity_Raw Materials", by_percent=0.2)
print(f"\nOriginal Profit: ${result.original_objective:,.2f}")
print(f"New Profit: ${result.new_objective:,.2f}")
print(f"Change: ${result.delta_objective:,.2f} ({result.delta_percentage:+.2f}%)")
print(f"\n⚠ Supply Risk: 20% material shortage would cost ${abs(result.delta_objective):,.2f}")
# ==================== BOTTLENECK IDENTIFICATION ====================
def identify_bottlenecks():
"""Identify bottlenecks by testing small capacity changes."""
print("\n" + "=" * 80)
print("BOTTLENECK IDENTIFICATION: Testing Resource Constraints")
print("=" * 80)
model = build_production_model()
optimizer = LXOptimizer().use_solver(solver_to_use)
whatif = LXWhatIfAnalyzer(model, optimizer)
# Find bottlenecks by testing 10 unit increases
# Note: Only testing resource capacity constraints (with constant RHS)
print("\nTesting impact of adding 10 units to each resource...")
test_amount = 10.0
improvements = []
# Manually test each resource capacity constraint
for resource in RESOURCES:
constraint_name = f"capacity_{resource.name}"
result = whatif.relax_constraint(constraint_name, by=test_amount)
improvement_per_unit = result.delta_objective / test_amount
improvements.append((constraint_name, improvement_per_unit))
# Sort by improvement (descending)
bottlenecks = sorted(improvements, key=lambda x: x[1], reverse=True)
print(f"\n{'Resource':<30s} {'Improvement':<20s} {'Per Unit':<15s} {'Priority':<10s}")
print("-" * 80)
Step 5: Compare Investment Options¶
print("BOTTLENECK ANALYSIS")
print("-" * 80)
if bottlenecks:
top_bottleneck, top_value = bottlenecks[0]
resource_name = top_bottleneck.replace("capacity_", "")
print(f"\n► Primary Bottleneck: {resource_name}")
print(f" Marginal Value: ${top_value:.2f} per unit")
print(f" Recommendation: Prioritize expanding this resource")
if top_value > 1.0:
print(f" ✓ HIGH PRIORITY: Strong ROI from capacity expansion")
print(f" - Each unit of capacity adds ${top_value:.2f} to profit")
print(f" - Consider immediate investment if cost < ${top_value:.2f}/unit")
elif top_value > 0.1:
print(f" → MODERATE PRIORITY: Positive ROI from expansion")
else:
print(f" ✗ LOW PRIORITY: Minimal profit impact")
# ==================== SENSITIVITY RANGE ANALYSIS ====================
def analyze_sensitivity_ranges():
"""Analyze how objective changes across range of parameter values."""
print("\n" + "=" * 80)
print("SENSITIVITY RANGE ANALYSIS: Parameter Impact Curves")
print("=" * 80)
model = build_production_model()
optimizer = LXOptimizer().use_solver(solver_to_use)
whatif = LXWhatIfAnalyzer(model, optimizer)
# Analyze labor capacity sensitivity
print("\n1. LABOR CAPACITY SENSITIVITY (700 - 1300 hours)")
print("-" * 80)
labor_range = whatif.sensitivity_range(
"capacity_Labor Hours", min_value=700, max_value=1300, num_points=13
)
print(f"\n{'Labor Hours':<15s} {'Profit':<20s} {'Marginal Value':<20s}")
print("-" * 80)
Learning Objectives¶
After completing this example, you should understand:
Quick Impact Assessment: Rapidly evaluate parameter changes
Bottleneck Discovery: Systematically find most valuable resources
ROI Calculation: Compare profit impact to investment cost
Risk Quantification: Measure downside of adverse changes
Investment Prioritization: Rank opportunities by marginal value
Interactive Analysis: Enable agile decision making
Common Patterns¶
Pattern 1: Quick Test¶
whatif = LXWhatIfAnalyzer(model, optimizer)
# Test single change
result = whatif.increase_constraint_rhs("capacity", by=100)
if result.delta_objective > 0:
print(f"Benefit: ${result.delta_objective:.2f}")
roi_per_unit = result.delta_objective / 100
print(f"ROI: ${roi_per_unit:.2f} per unit")
Pattern 2: Decision Logic¶
result = whatif.increase_constraint_rhs("labor", by=100)
cost = 25.0 * 100 # $25/hour × 100 hours
benefit = result.delta_objective
net = benefit - cost
if net > 0:
print(f"✓ INVEST: Net benefit = ${net:.2f}")
else:
print(f"✗ DON'T INVEST: Net loss = ${abs(net):.2f}")
Pattern 3: Systematic Testing¶
# Test all resource constraints
resources = ["Labor", "Machine", "Material"]
for resource in resources:
constraint_name = f"capacity_{resource}"
result = whatif.relax_constraint(constraint_name, by=10.0)
marginal = result.delta_objective / 10.0
print(f"{resource}: ${marginal:.2f} per unit")
Business Decision Examples¶
Hiring Decision¶
# Test hiring 4 new workers (40 hours/week each)
result = whatif.increase_constraint_rhs("capacity_Labor", by=160)
# Cost analysis
hourly_wage = 25.0
total_cost = hourly_wage * 160
profit_increase = result.delta_objective
net_benefit = profit_increase - total_cost
print(f"Cost: ${total_cost:.2f}")
print(f"Benefit: ${profit_increase:.2f}")
print(f"Net: ${net_benefit:.2f}")
if net_benefit > 0:
payback_weeks = total_cost / (profit_increase / 52)
print(f"Payback: {payback_weeks:.1f} weeks")
Equipment Investment¶
# Test purchasing new machine (200 additional hours/week)
result = whatif.increase_constraint_rhs("capacity_Machine", by=200)
equipment_cost = 50000.0 # One-time cost
annual_benefit = result.delta_objective * 52 # 52 weeks/year
payback_years = equipment_cost / annual_benefit
print(f"Equipment Cost: ${equipment_cost:,.0f}")
print(f"Annual Benefit: ${annual_benefit:,.0f}")
print(f"Payback Period: {payback_years:.1f} years")
Risk Assessment¶
# Test supply chain disruption (30% material shortage)
result = whatif.tighten_constraint("capacity_Materials", by_percent=0.3)
expected_loss = abs(result.delta_objective)
loss_percent = abs(result.delta_percentage)
print(f"⚠ Risk: 30% material shortage")
print(f"Expected Loss: ${expected_loss:,.2f} ({loss_percent:.1f}%)")
What-If Result Structure¶
Each analysis returns LXWhatIfResult:
result.description # Description of change
result.original_objective # Baseline objective
result.new_objective # New objective after change
result.delta_objective # Change in objective
result.delta_percentage # Percentage change
result.original_solution # Baseline solution
result.new_solution # New solution
result.changes_applied # List of modifications
What-If vs Scenario Analysis¶
Use What-If Analysis when:
Need quick tactical decisions
Testing single parameter changes
Exploring sensitivity ranges
Finding bottlenecks
Time-sensitive decisions
Use Scenario Analysis when:
Complex multi-parameter changes
Strategic planning (long-term)
Comparing business scenarios
Formal reporting required
Need reproducible scenarios
Advantages of What-If¶
Speed¶
Immediate feedback on changes
No scenario setup required
Interactive exploration
Quick iteration
Simplicity¶
Simple API for common changes
Intuitive constraint manipulation
No model structure knowledge needed
Flexibility¶
Test any parameter change
Compare multiple options
Customize to specific needs
Decision Support¶
Clear ROI calculations
Risk quantification
Investment prioritization
Actionable insights
Extending the Example¶
Try These Modifications¶
Variable Bounds: Modify variable upper/lower bounds
Cost Changes: Test objective coefficient changes
Multiple Changes: Combine several parameter modifications
Time Series: Analyze changes over multiple periods
Probabilistic: Add Monte Carlo for risk assessment
Next Steps¶
After mastering this example:
Example 08 (Scenario Analysis): Strategic planning scenarios
Example 09 (Sensitivity Analysis): Shadow prices and reduced costs
Interactive Dashboards: Build real-time decision support tools
See Also¶
Related Examples:
Scenario Analysis Example - Strategic planning with scenarios
Sensitivity Analysis Example - Understanding shadow prices
Production Planning Example - Base model for what-if
API Reference:
lumix.analysis.LXWhatIfAnalyzerlumix.analysis.LXWhatIfResult
Files in This Example¶
whatif_analysis.py- Main what-if analysis demonstrationsample_data.py- Data models (Product, Resource) and sample dataREADME.md- Detailed documentation and usage guide