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 setting with:
- Demand PMF from a discrete KDE (previous lesson), with moments .
- Lead-time PMF, for example:
| Lead time | 3 | 4 | 5 |
|---|---|---|---|
| Probability | 0.1 | 0.7 | 0.2 |
- Holding cost per unit per period, fixed order cost , and a backlog cost charged per unit short per period (not a one-shot backorder fee).
Three building blocks:
- Estimate demand and lead-time distributions (and their moments).
- Write a simulator that maps a candidate safety stock (given ) to average cost and service KPIs.
- Run a search over until a stopping rule fires.
From safety stock to order-up-to:
Use mean lead time 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):
- Maintain on-hand (can go negative under backlog) and a transit pipeline sized to the maximum lead time.
- Each period: receive due receipts, observe demand, update on-hand and stockout flags, advance the pipeline.
- Every 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 .
- Accrue holding on average physical stock, backlog cost , and transaction cost when ordering.
- Return average cost per period, cycle service, fill rate, and the you tested.
Long horizons (e.g. tens of thousands of periods) reduce noise but raise runtime.
Search method 1: start at zero and climb
- Simulate (often 0).
- Step .
- If the new cost is better than the best so far, update the best.
- Stop when the latest cost exceeds .
Step size : often – 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 often wastes iterations in a high-cost region.
Search method 2: heuristic start and double run
- Pick a heuristic near the analytical optimum under Normal assumptions.
- Search upward with and downward with from that seed (or from seed for the decrease pass).
- Keep the best policy seen across both runs.
Heuristic seed for
If you temporarily pretend demand and lead time are Normal, a backlog-style service target is
With time-based backlog cost , inflate slightly in the heuristic (e.g. ) so multi-period shortage penalty is not understated:
Protection-period standard deviation with uncertain lead time:
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 to locate the valley, then fine around the winner.
- Faster simulation code (vectorization, fewer allocations).
- Smooth noisy costs (e.g. local average of neighboring 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
: nest searches
- Seed (e.g. power-of-two ideas from deterministic review design).
- Optimize for that with the methods above.
- Try shorter and longer ; optimize for each.
- Keep expanding in the improving direction until neighbors no longer win.
: harder analytically, natural for sim-opt
Every periods, if inventory position , order (or enough multiples of to clear the gap).
If review itself is free, prefer small and let carry the fixed-order-cost trade-off. If counting inventory is costly, search over as well.
Heuristic starts (wisdom-of-crowd style averages):
(again inflate if you only observe ).
Risk period for the buffer: between and , a practical compromise is :
(with lead-time variance folded in as in the protection formula when is random).
Order quantity: start from EOQ , optionally one stochastic refinement with a rough (e.g. a small fraction of ).
Pack into a vector and hand it to a black-box minimizer (e.g. SciPy Nelder–Mead) whose objective is the simulated average cost. Round and 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:
- Fix a random seed (
np.random.seed(...)) for reproducible comparisons—not a cure for every parameter change. - Lengthen the horizon to cut variance (slower, but better chance of a policy that was not lucky on a short run).
- 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
Simulation optimization ideas
1 / 5When is simulation optimization most justified?
Pick an answer to see if you are right.
Rank a safety-stock sim-opt
Run a one-parameter sim-opt
1 / 1You have demand and lead-time PMFs and want a good Ss for fixed R.
OrderDrag the handle to rearrange — top should be first.
- 1Publish S = Ss + μ_d(μ_L + R) from the best Ss, and update the live policy only if improvement is material.
- 2Estimate μ_d, σ_d, μ_L, σ_L from the PMFs.
- 3Seed Ss with the Normal-style α*/σ_x heuristic; also search downward with −Δ.
- 4Build a simulator that returns average cost for a candidate Ss.
- 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 .
Code: threshold climb search
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 , then averaged and with risk length (fixed 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 and ; pack 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.