Optimization Under Uncertainty: Scenarios & Robustness

10 min read Module 3 of 9 Lesson 9 of 25

What you'll learn

  • Formulate a two-stage stochastic program using sampled scenarios (sample average approximation)
  • Apply robust optimization with uncertainty sets, and control its conservatism with an uncertainty budget
  • Express risk limits with chance constraints and optimize tail risk with CVaR
  • Choose between expected-value, stochastic, robust and risk-averse formulations for a given decision
Building this at your company? For enterprise and company teams taking this to production: book a 30-minute session with our AI engineers for architecture guidance, code review, and a rollout plan for your use case.
Book a Team Session

The last two lessons fed point estimates into an optimizer and dealt with the consequences. This lesson takes the uncertainty seriously from the start. Lesson 6 gave you quantiles, intervals and, implicitly, distributions over outcomes. Now the optimizer gets to see them.

There are three main families of methods, and they differ mainly in what they assume about the uncertainty and how pessimistic they are:

  • Stochastic programming: optimize the expected outcome over a set of scenarios.
  • Robust optimization: optimize the worst case over an uncertainty set.
  • Risk-averse optimization: optimize or constrain a risk measure, such as tail losses or the probability of failure.

Why point forecasts give fragile plans

Take an inventory problem with a shared warehouse. Plug in the mean demand forecast for each SKU and the optimizer fills the warehouse exactly to match. Any SKU that sells above forecast stocks out; any that sells below wastes space that another SKU needed. The plan is optimal for one future, the average one, which will not happen.

This “flaw of averages” is general. The value of a plan evaluated at average inputs is not the average value of the plan across possible inputs, whenever there are capacities, minimums, or any other non-linearity. And business decisions are full of them.

Stochastic programming with scenarios

The most practical approach: generate a few hundred scenarios of the uncertain quantities (from quantile models, conformal intervals, simulation, or bootstrapped history) and optimize the average outcome across them.

The key modeling idea is two stages. First-stage decisions are made now, before uncertainty resolves (how much of each SKU to order). Second-stage recourse decisions are made after, separately in each scenario (how much to sell, whether to expedite, what to mark down). The optimizer chooses the first stage knowing it’ll be able to react in the second.

from ortools.linear_solver import pywraplp

def order_plan(skus, scenarios, price, cost, salvage, capacity):
    """scenarios: list of dicts {sku: demand}, equally likely.
    Sample average approximation of a two-stage newsvendor
    with a shared warehouse capacity."""
    S = len(scenarios)
    solver = pywraplp.Solver.CreateSolver("GLOP")  # pure LP

    # Stage 1: order quantities, same in every scenario
    q = {k: solver.NumVar(0, solver.infinity(), f"q[{k}]") for k in skus}
    solver.Add(solver.Sum(q.values()) <= capacity)

    # Stage 2: sales per scenario, limited by stock and demand
    profit_terms = []
    for s, demand in enumerate(scenarios):
        for k in skus:
            sold = solver.NumVar(0, demand[k], f"sold[{s},{k}]")
            solver.Add(sold <= q[k])
            # leftover (q - sold) is salvaged at a loss
            profit_terms.append((price[k] - salvage[k]) * sold / S)

    total_cost = solver.Sum((cost[k] - salvage[k]) * q[k] for k in skus)
    solver.Maximize(solver.Sum(profit_terms) - total_cost)
    solver.Solve()
    return {k: q[k].solution_value() for k in skus}

This is called sample average approximation (SAA). With one SKU and no capacity, it reproduces the newsvendor quantile from Lesson 6. With a shared capacity, it does something the per-SKU rule can’t: it decides which SKUs deserve buffer stock given that space is limited, favouring those with high margins and volatile demand.

Two practical notes. Scenario quality matters more than scenario count: they need realistic correlation between items (a heatwave lifts all cold drinks together). And check stability: solve with several independent scenario sets; if the plans differ a lot, you need more scenarios.

Robust optimization

Stochastic programming needs a probability distribution. Sometimes you don’t trust one, or the stakes demand protection against bad cases regardless of their probability. Robust optimization asks instead: find the plan that performs best in the worst case over an uncertainty set, such as every demand vector within its conformal interval.

Protecting against every parameter hitting its worst value simultaneously is usually absurdly conservative. If 500 SKUs each have a 90% interval, the chance that all of them land at the top of their intervals at once is negligible. The budget of uncertainty approach (Bertsimas and Sim) limits how many parameters can deviate to their worst case together, with a parameter Γ:

  • Γ = 0 gives the nominal plan (no protection).
  • Γ = number of parameters gives full worst-case protection.
  • In between, a tunable dial. A Γ around a few times the square root of the number of parameters often gives strong protection at modest cost.

Robust formulations remain LPs or MIPs (the worst case can be dualized into extra constraints), so they run in the same solvers. Use robust optimization when constraint violations are unacceptable (capacity you physically can’t exceed, safety limits), and when you’d rather pay a known premium than trust a distribution.

Chance constraints

Often the business states the requirement as a probability: “the chance of a stockout on critical parts must be under 2%”, “the probability of overspending the budget must be under 5%”. These are chance constraints.

With scenarios, approximate them directly: add a binary indicator per scenario for “constraint violated here” and require at most 2% of scenarios to have it switched on. This makes the model a MIP, which is fine for moderate scenario counts. For a single uncertain quantity, it’s simpler: a chance constraint P(demand ≤ stock) ≥ 0.98 is just stock ≥ the 98th percentile of demand, which a quantile model or conformal interval gives you directly.

Risk measures: CVaR

Expected-value objectives are risk-neutral: a plan that earns $10M on average with a 3% chance of losing $50M looks better than one that earns $9M with no chance of loss. Many businesses aren’t risk-neutral, for good reason.

Conditional value at risk (CVaR) at level 95% is the average loss in the worst 5% of scenarios. It’s a well-behaved risk measure, and with scenarios it’s linear-programmable (Rockafellar and Uryasev), so you can:

  • Maximize expected profit subject to CVaR₉₅ of loss ≤ some limit, or
  • Maximize a blend: expected profit − β × CVaR, where β expresses risk aversion.

This is how portfolio managers, insurers and energy traders set positions, and it’s directly useful for any decision with heavy-tailed downside: credit portfolios, large inventory bets, capacity commitments.

Choosing a formulation

SituationFormulation
Costs roughly linear, no capacity limits, risk-neutralExpected value (point forecasts) is fine
Shared capacity, recourse available, trustworthy distributionsTwo-stage stochastic (SAA)
Violations unacceptable, distributions untrustedRobust with budgeted uncertainty
Requirement stated as a probabilityChance constraint
Rare large losses are unacceptableCVaR objective or constraint

Always compare against the expected-value plan on held-out scenarios. The difference, called the value of the stochastic solution, tells you whether the extra modeling is buying anything. Sometimes it’s 0.5% and not worth the complexity. Often, for capacity-constrained or heavy-tailed problems, it’s 5 to 15%.

That completes the optimization layer. But every value the optimizer has used so far assumed we knew the effect of each action. Module 4 tackles the hardest part of decision modeling: estimating what an action actually changes.

Knowledge Check

4 questions to test your understanding

1 In a two-stage stochastic program for inventory, what distinguishes first-stage from second-stage decisions?

2 A robust optimization model protects against every demand value in the full forecast interval for all 500 SKUs simultaneously. Plans are very expensive. What is the standard fix?

3 The business says 'the probability of running out of a critical part must be below 2%'. What kind of constraint is this?

4 Why might a business prefer to optimize CVaR (expected loss in the worst 5% of outcomes) rather than expected profit?

Go further with expert guidance

Ready to build production AI?
Talk to our R&D team.

These courses give you the foundation. Our embedded AI teams take you from prototype to production in 30–90 days, with your team, your codebase, your goals. Book a free strategy call to see how we can accelerate your AI initiative.

30 minutes · No obligation · Expert AI engineers, not sales reps

AI Architecture Review

Audit your current stack and identify high-impact improvements

Project Review

Get expert feedback on your AI implementation and codebase

Team Mentoring

Upskill your engineers with hands-on AI coaching sessions

AI Strategy

Define your AI roadmap, prioritization, and implementation plan