| name | stochastic-optimization |
| description | When the user wants to optimize under uncertainty, handle probabilistic constraints, or solve stochastic programming problems. Also use when the user mentions "stochastic optimization," "chance constraints," "two-stage stochastic programming," "scenario-based optimization," "robust optimization under uncertainty," "stochastic demand," "uncertainty modeling," or "probabilistic optimization." For deterministic optimization, see optimization-modeling. For robust optimization, see metaheuristic-optimization. |
Stochastic Optimization
You are an expert in stochastic optimization and decision-making under uncertainty for supply chain. Your goal is to help solve optimization problems where parameters (demand, lead times, prices) are uncertain, using scenario-based methods, chance constraints, and risk measures.
Initial Assessment
Before applying stochastic optimization, understand:
-
Uncertainty Characteristics
- What parameters are uncertain? (demand, supply, prices, lead times)
- Probability distributions known or unknown?
- Historical data available?
- Uncertainty independent or correlated?
-
Decision Structure
- Single-stage or multi-stage decisions?
- Which decisions made before/after uncertainty reveals?
- Recourse actions available?
- Decision frequency?
-
Risk Attitude
- Risk-neutral (expected value) or risk-averse?
- Preferred risk measure? (CVaR, variance, worst-case)
- Service level requirements?
- Budget/capacity constraints?
-
Computational Requirements
- Problem size?
- Number of scenarios needed?
- Solution time constraints?
- Need for exact vs approximate solution?
Two-Stage Stochastic Programming
Framework
Stage 1 (Here-and-Now): Decisions before uncertainty revealed
Stage 2 (Wait-and-See): Recourse decisions after observing uncertainty
Formulation:
min c^T x + E_ξ[Q(x, ξ)]
s.t. Ax = b
x ≥ 0
where Q(x, ξ) = min q(ξ)^T y
s.t. W y = h(ξ) - T(ξ) x
y ≥ 0
Implementation: Production Planning Under Demand Uncertainty
import numpy as np
from pulp import *
from typing import List, Dict, Tuple
import matplotlib.pyplot as plt
class TwoStageStochasticProduction:
"""
Two-Stage Stochastic Programming for Production Planning
Stage 1: Decide production quantities (before demand known)
Stage 2: Handle inventory/backorder (after demand realized)
"""
def __init__(self,
products: List[str],
scenarios: List[Dict],
production_cost: Dict[str, float],
holding_cost: Dict[str, float],
backorder_cost: Dict[str, float],
capacity: float):
"""
Initialize two-stage stochastic model
products: list of product names
scenarios: list of dicts with {'demand': {product: qty}, 'probability': p}
production_cost: cost per unit to produce
holding_cost: cost per unit to hold inventory
backorder_cost: cost per unit backorder
capacity: production capacity
"""
self.products = products
self.scenarios = scenarios
self.n_scenarios = len(scenarios)
self.prod_cost = production_cost
self.hold_cost = holding_cost
self.back_cost = backorder_cost
.capacity = capacity
.solution =
() -> :
()
()
model = LpProblem(, LpMinimize)
produce = LpVariable.dicts(, .products, lowBound=)
inventory = {}
backorder = {}
s, scenario (.scenarios):
p .products:
inventory[(s, p)] = LpVariable(, lowBound=)
backorder[(s, p)] = LpVariable(, lowBound=)
stage1_cost = lpSum([.prod_cost[p] * produce[p] p .products])
stage2_cost = lpSum([
.scenarios[s][] * (
.hold_cost[p] * inventory[(s, p)] +
.back_cost[p] * backorder[(s, p)]
)
s (.n_scenarios)
p .products
])
model += stage1_cost + stage2_cost,
model += lpSum([produce[p] p .products]) <= .capacity,
s, scenario (.scenarios):
p .products:
demand = scenario[][p]
model += (
produce[p] + backorder[(s, p)] ==
demand + inventory[(s, p)]
),
model.solve(PULP_CBC_CMD(msg=))
LpStatus[model.status] == :
production_plan = {p: produce[p].varValue p .products}
scenario_solutions = []
s, scenario (.scenarios):
scenario_sol = {
: s,
: scenario[],
: scenario[],
: {p: inventory[(s, p)].varValue p .products},
: {p: backorder[(s, p)].varValue p .products}
}
scenario_solutions.append(scenario_sol)
.solution = {
: ,
: value(model.objective),
: (.prod_cost[p] * production_plan[p]
p .products),
: value(model.objective) -
(.prod_cost[p] * production_plan[p]
p .products),
: production_plan,
: scenario_solutions
}
.solution
:
{: LpStatus[model.status]}
():
.solution:
()
( + *)
()
(*)
()
()
()
()
product, qty .solution[].items():
cost = qty * .prod_cost[product]
()
()
scenario_sol .solution[]:
s = scenario_sol[]
prob = scenario_sol[]
()
()
()
()
inv_cost = (.hold_cost[p] * scenario_sol[][p]
p .products)
back_cost = (.back_cost[p] * scenario_sol[][p]
p .products)
()
():
.solution:
fig, axes = plt.subplots(, (.products),
figsize=(*(.products), ))
(.products) == :
axes = [axes]
idx, product (.products):
ax = axes[idx]
production = .solution[][product]
scenarios = []
demands = []
probs = []
scenario_sol .solution[]:
scenarios.append()
demands.append(scenario_sol[][product])
probs.append(scenario_sol[])
x = np.arange((scenarios))
bars = ax.bar(x, demands, color=,
edgecolor=, linewidth=)
bar, prob (bars, probs):
bar.set_alpha(prob * )
ax.axhline(y=production, color=, linewidth=,
linestyle=, label=)
ax.set_xlabel(, fontsize=)
ax.set_ylabel(, fontsize=)
ax.set_title(, fontsize=, fontweight=)
ax.set_xticks(x)
ax.set_xticklabels(scenarios)
ax.legend()
ax.grid(, axis=, alpha=)
plt.tight_layout()
plt.show()
__name__ == :
products = [, , ]
np.random.seed()
scenarios = [
{
: {: , : , : },
:
},
{
: {: , : , : },
:
},
{
: {: , : , : },
:
}
]
production_cost = {: , : , : }
holding_cost = {: , : , : }
backorder_cost = {: , : , : }
optimizer = TwoStageStochasticProduction(
products=products,
scenarios=scenarios,
production_cost=production_cost,
holding_cost=holding_cost,
backorder_cost=backorder_cost,
capacity=
)
result = optimizer.optimize()
optimizer.print_solution()
optimizer.plot_solution()
Chance-Constrained Optimization
Probabilistic Constraints
Chance Constraint:
P(g(x, ξ) ≤ 0) ≥ α
where α is reliability level (e.g., 95%)
Implementation: Inventory with Service Level
import numpy as np
from scipy import stats
from scipy.optimize import minimize
class ChanceConstrainedInventory:
"""
Inventory Optimization with Service Level Constraints
Minimize cost subject to probabilistic service level
"""
def __init__(self,
products: List[str],
demand_mean: Dict[str, float],
demand_std: Dict[str, float],
holding_cost: Dict[str, float],
service_level: float = 0.95):
"""
Initialize chance-constrained model
service_level: probability of meeting demand (e.g., 0.95 = 95%)
"""
self.products = products
self.demand_mean = demand_mean
self.demand_std = demand_std
self.holding_cost = holding_cost
self.service_level = service_level
self.z_alpha = stats.norm.ppf(service_level)
def optimize(self):
"""
Optimize inventory levels
For normal distribution, chance constraint becomes:
s ≥ μ + z_α * σ
where s = stock level, μ = mean demand, σ = std dev
"""
print(f"Optimizing Inventory with Service Level")
results = {}
total_cost =
product .products:
mu = .demand_mean[product]
sigma = .demand_std[product]
h = .holding_cost[product]
optimal_stock = mu + .z_alpha * sigma
cost = h * optimal_stock
total_cost += cost
results[product] = {
: optimal_stock,
: .z_alpha * sigma,
: mu,
: cost,
: .service_level
}
{
: results,
: total_cost,
: .service_level
}
products = [, , ]
demand_mean = {: , : , : }
demand_std = {: , : , : }
holding_cost = {: , : , : }
optimizer = ChanceConstrainedInventory(
products, demand_mean, demand_std, holding_cost,
service_level=
)
result = optimizer.optimize()
()
product, data result[].items():
(
)
Sample Average Approximation (SAA)
Method
Approximate E[f(x,ξ)] with sample average:
(1/N) Σ f(x, ξ_i)
where ξ_1, ..., ξ_N are sampled scenarios
Implementation
def sample_average_approximation(problem, n_samples=1000, n_replications=10):
"""
SAA method for stochastic optimization
1. Generate N scenarios
2. Solve deterministic equivalent
3. Repeat M times
4. Select best solution
"""
best_solution = None
best_objective = float('inf')
for rep in range(n_replications):
scenarios = problem.generate_scenarios(n_samples)
solution = problem.solve_deterministic(scenarios)
test_scenarios = problem.generate_scenarios(n_samples)
objective = problem.evaluate(solution, test_scenarios)
if objective < best_objective:
best_objective = objective
best_solution = solution
return best_solution, best_objective
Risk Measures
Conditional Value-at-Risk (CVaR)
def optimize_with_cvar(scenarios, alpha=0.95):
"""
Minimize CVaR (expected cost in worst α% cases)
CVaR_α(X) = E[X | X ≥ VaR_α(X)]
"""
model = LpProblem("CVaR_Optimization", LpMinimize)
x = LpVariable.dicts("x", products, lowBound=0)
var = LpVariable("VaR", lowBound=None)
z = LpVariable.dicts("z", range(len(scenarios)), lowBound=0)
model += var + (1/(1-alpha)) * lpSum([
scenarios[s]['prob'] * z[s]
for s in range(len(scenarios))
]), "CVaR"
for s in range(len(scenarios)):
cost_s = calculate_cost(x, scenarios[s])
model += z[s] >= cost_s - var, f"CVaR_s{s}"
model.solve()
return {
'solution': {p: x[p].varValue for p in products},
'VaR': var.varValue,
'CVaR': value(model.objective)
}
Multi-Stage Stochastic Programming
Scenario Tree
Stage 1 → Stage 2 → Stage 3
x₁ → x₂(ξ₁) → x₃(ξ₁,ξ₂)
→ x₂(ξ₂) → x₃(ξ₂,ξ₃)
Dynamic Programming Approach
def multistage_inventory_dp(T, scenarios_per_stage):
"""
Multi-stage inventory control with dynamic programming
T: number of stages
scenarios_per_stage: number of scenarios at each stage
"""
V = [{} for _ in range(T+1)]
V[T] = {state: 0 for state in states}
for t in range(T-1, -1, -1):
for state in states:
min_cost = float('inf')
best_action = None
for action in actions:
expected_cost = 0
for scenario in scenarios[t]:
next_state = transition(state, action, scenario)
prob = scenario['probability']
immediate_cost = cost(state, action, scenario)
future_cost = V[t+1][next_state]
expected_cost += prob * (immediate_cost + future_cost)
if expected_cost < min_cost:
min_cost = expected_cost
best_action = action
V[t][state] = min_cost
return V
Tools & Libraries
Python:
scipy.stats: probability distributions
numpy: random sampling
pulp/pyomo: stochastic programming formulation
SALib: sensitivity analysis
Specialized:
PySP (Pyomo): stochastic programming extension
StochOptim.jl (Julia): stochastic optimization
Commercial:
CPLEX Stochastic Solver
Gurobi Multi-Scenario
Related Skills
- optimization-modeling: deterministic optimization
- demand-forecasting: uncertainty modeling
- inventory-optimization: stochastic inventory
- risk-mitigation: risk management
- scenario-planning: scenario generation