Skip to main content

12. Simulation Optimization

Closed-form inventory models need strong assumptions: Normal or gamma demand, fixed or Normal lead times, pure backorders, non-perishable stock. Real chains often violate several of those at once—custom demand shapes from the previous lesson, stochastic lead times, time-dependent backlog penalties, partial lost sales, or product aging.

Simulation optimization (sim-opt) does not solve those cases with a single equation. It simulates many candidate policies and keeps the one with the best estimated cost (or another KPI). The price is compute time and noisy estimates; the gain is workable policies when math is intractable.

Original teaching rewrite for this course. Numbers in drills are constructed for stable grading; they follow the chapter’s logic without reprinting a commercial case study.

When mathematical models stop being enough​

Typical breaks in earlier assumptions:

  • Excess demand is partly lost sales, or backlog that ages into cancellations—not a fixed per-unit backorder cost.
  • Demand follows a custom discrete PMF (KDE), not Normal/gamma.
  • Lead time is itself a discrete PMF.
  • Goods deteriorate or perish within a short horizon.

If you cannot write a trustworthy closed form, simulate the policy and search.

Case: safety stock with custom demand and lead time​

Consider a periodic (R,S)(R,S) setting with:

  • Demand PMF from a discrete KDE (previous lesson), with moments μd,σd\mu_d,\sigma_d.
  • Lead-time PMF, for example:
Lead time LL345
Probability0.10.70.2
  • Holding cost hh per unit per period, fixed order cost kk, and a backlog cost bτb_\tau charged per unit short per period (not a one-shot backorder fee).

Three building blocks:

  1. Estimate demand and lead-time distributions (and their moments).
  2. Write a simulator that maps a candidate safety stock SsS_s (given RR) to average cost and service KPIs.
  3. Run a search over SsS_s until a stopping rule fires.

From safety stock to order-up-to:

S=Ss+μd(μL+R)S = S_s + \mu_d(\mu_L + R)

Use mean lead time μL\mu_L in that formula—not only the modal (“most common”) lead time—unless your model explicitly says otherwise.

Simulation sketch​

A practical discrete-time loop (same spirit as earlier policy labs):

  1. Maintain on-hand (can go negative under backlog) and a transit pipeline sized to the maximum lead time.
  2. Each period: receive due receipts, observe demand, update on-hand and stockout flags, advance the pipeline.
  3. Every RR periods: compute inventory position (on-hand + pipeline), sample a random lead time from the lead-time PMF, and place an order that restores position to SS.
  4. Accrue holding on average physical stock, backlog cost bτ⋅max⁡(0,−on-hand)b_\tau\cdot\max(0,-\text{on-hand}), and transaction cost kk when ordering.
  5. Return average cost per period, cycle service, fill rate, and the SsS_s you tested.

Long horizons (e.g. tens of thousands of periods) reduce noise but raise runtime.

Search method 1: start at zero and climb​

  1. Simulate Ss=startS_s=\texttt{start} (often 0).
  2. Step Ss←Ss+ΔS_s \leftarrow S_s + \Delta.
  3. If the new cost is better than the best so far, update the best.
  4. Stop when the latest cost exceeds threshold×best cost\texttt{threshold}\times\text{best cost}.

Step size Δ\Delta: often 1%1\%–5%5\% of mean demand, or a practical batch size (e.g. 100).

Threshold: larger values explore farther past the valley but cost more iterations. Simulation noise can trip a tight threshold early—raise the threshold or lengthen the horizon when the chain is more random.

Starting at Ss=0S_s=0 often wastes iterations in a high-cost region.

Search method 2: heuristic start and double run​

  1. Pick a heuristic SsS_s near the analytical optimum under Normal assumptions.
  2. Search upward with +Δ+\Delta and downward with −Δ-\Delta from that seed (or from seed −Δ-\Delta for the decrease pass).
  3. Keep the best policy seen across both runs.

Heuristic seed for (R,S)(R,S)​

If you temporarily pretend demand and lead time are Normal, a backlog-style service target is

α∗≈1−hRb\alpha^* \approx 1-\frac{hR}{b}

With time-based backlog cost bτb_\tau, inflate bb slightly in the heuristic (e.g. 1.1 bτ1.1\,b_\tau) so multi-period shortage penalty is not understated:

α∗≈1−hR1.1 bτ\alpha^* \approx 1-\frac{hR}{1.1\,b_\tau}

Protection-period standard deviation with uncertain lead time:

σx=(μL+R)σd2+σL2μd2\sigma_x=\sqrt{(\mu_L+R)\sigma_d^2+\sigma_L^2\mu_d^2} Ss≈zα∗ σx,zα∗=Φ−1(α∗)S_s \approx z_{\alpha^*}\,\sigma_x,\qquad z_{\alpha^*}=\Phi^{-1}(\alpha^*)

That seed is not “the” optimum under a custom PMF—it is a warm start for sim-opt.

Further search ideas​

  • Two-loop grid: coarse Δ\Delta to locate the valley, then fine Δ\Delta around the winner.
  • Faster simulation code (vectorization, fewer allocations).
  • Smooth noisy costs (e.g. local average of neighboring SsS_s evaluations) instead of only lengthening the horizon.
  • Variable step from the local slope; or fit a curve / use a black-box optimizer after a few evaluations.

Multi-parameter policies​

(R,S)(R,S): nest searches​

  1. Seed RR (e.g. power-of-two ideas from deterministic review design).
  2. Optimize SsS_s for that RR with the methods above.
  3. Try shorter and longer RR; optimize SsS_s for each.
  4. Keep expanding RR in the improving direction until neighbors no longer win.

(R,s,Q)(R,s,Q): harder analytically, natural for sim-opt​

Every RR periods, if inventory position ≤s\le s, order QQ (or enough multiples of QQ to clear the gap).

If review itself is free, prefer small RR and let QQ carry the fixed-order-cost trade-off. If counting inventory is costly, search over RR as well.

Heuristic starts (wisdom-of-crowd style averages):

α≈12[(1−hRb)+(1−hQbD)]\alpha \approx \tfrac12\left[\left(1-\frac{hR}{b}\right)+\left(1-\frac{hQ}{bD}\right)\right]

(again inflate bb if you only observe bτb_\tau).

Risk period for the buffer: between LL and L+RL+R, a practical compromise is L+R/2L+R/2:

Ss=zσdL+R/2,s=μd(L+R/2)+SsS_s=z\sigma_d\sqrt{L+R/2},\qquad s=\mu_d(L+R/2)+S_s

(with lead-time variance folded in as in the (R,S)(R,S) protection formula when LL is random).

Order quantity: start from EOQ 2kD/h\sqrt{2kD/h}, optionally one stochastic refinement 2(k+bUs)D/h\sqrt{2(k+bU_s)D/h} with a rough UsU_s (e.g. a small fraction of QQ).

Pack (s,Q)(s,Q) into a vector and hand it to a black-box minimizer (e.g. SciPy Nelder–Mead) whose objective is the simulated average cost. Round ss and QQ inside the simulator. Cap iterations (maxiter) so the search stays affordable.

Stability: sim-opt results move​

Two runs rarely return identical policies. Noise comes from random demand, lead times, and finite horizons. Planners dislike jittery parameter updates (bullwhip risk and trust erosion).

Three mitigations:

  1. Fix a random seed (np.random.seed(...)) for reproducible comparisons—not a cure for every parameter change.
  2. Lengthen the horizon to cut variance (slower, but better chance of a policy that was not lucky on a short run).
  3. Update only on material improvement—e.g. adopt a new policy only if estimated cost falls by at least 5% versus the current live policy under the same cost assumptions.

Seeds help demos; significant-change rules help production stability; longer sims help both reliability and fairness in scenario studies.

Practice​

Concept check​

Quiz

Simulation optimization ideas

1 / 5

When is simulation optimization most justified?

Pick an answer to see if you are right.

Rank a safety-stock sim-opt​

Quiz

Run a one-parameter sim-opt

1 / 1

You have demand and lead-time PMFs and want a good Ss for fixed R.

OrderDrag the handle to rearrange — top should be first.

  1. 1Publish S = Ss + μ_d(μ_L + R) from the best Ss, and update the live policy only if improvement is material.
  2. 2Estimate μ_d, σ_d, μ_L, σ_L from the PMFs.
  3. 3Seed Ss with the Normal-style α*/σ_x heuristic; also search downward with −Δ.
  4. 4Build a simulator that returns average cost for a candidate Ss.
  5. 5Climb upward with +Δ and a cost-ratio stop from that seed.

Drag items into the correct order (or use ↑↓), then check.

Code: heuristic safety-stock seed​

Implement the Normal-style warm start used before sim-opt. Use statistics.NormalDist().inv_cdf for Φ−1\Phi^{-1}.

Given a deterministic cost oracle cost_fn(ss) (stand-in for a long simulation), implement the climb search from Method 1. Support positive and negative step sizes.

Code: material policy update gate​

Return whether to replace the live policy given old/new estimated costs and a minimum relative improvement.

Code: (R, s, Q) warm-start quantities​

One iteration of stochastic EOQ-style QQ, then averaged α\alpha and ss with risk length L+R/2L+R/2 (fixed LL here for the drill).

Takeaways​

  • Use sim-opt when shortage regimes, custom PMFs, random lead times, or perishability break closed forms.
  • Pipeline: model distributions → simulate cost(policy) → search (climb, double search, or black-box).
  • Warm-start from Part III heuristics; search both directions with a cost-ratio stop.
  • Nest searches for RR and SsS_s; pack (s,Q)(s,Q) for multi-parameter optimizers.
  • Stabilize with seeds, longer horizons, and material improvement before changing live policies.

Previous: Discrete Probabilistic Demand.

Next: Return to Inventory Policies and apply the full toolkit—or revisit MEIO and newsvendor as needed.