Spending a Budget, and the Tools

Manuel D. Rossetti, PhD P.E.

Agenda

  • The allocation problem, and marginal analysis by delta value
  • Why two echelons break convexity, convexification, and flushout
  • Many items under one budget, and the procedure that returns a curve
  • The workbook: the depot first, and pricing a repair contract on the sheets
  • The software: one class for two models, two searches, and a budget priced instead of enforced

What Is Being Chosen, and Against What

A stock level at the depot and one at each storeroom, for every item. Nine items and four storerooms is forty-five numbers, competing for the same money. Minimize the total expected backorders at the storerooms,

\[ \mathit{EBO} = \sum_{\text{items}}\;\sum_{j=1}^{J}\bar{B}_j(S_j) \qquad\text{subject to}\qquad \sum_{\text{items}}\Big(c_0S_0 + \sum_{j=1}^{J}c_jS_j\Big) \le \text{budget} \]

where \(c_j\) and \(c_0\) represent the item’s unit cost at storeroom \(j\) and at the depot.

Notice what the objective leaves out

No crew waits at a depot, so a depot backorder costs nothing directly. It costs by lengthening \(\bar{W}\), which inflates every storeroom’s pipeline. Depot stock is valued entirely for what it does elsewhere, which is what makes this one multi-echelon problem rather than five separate ones.

Marginal Analysis

For each item and location, the delta value is what the next unit buys per dollar. Recall that the next unit removes \(G^{0}(S)\) backorders:

\[ \delta(S) = \frac{\bar{B}(S) - \bar{B}(S+1)}{c} = \frac{G^{0}(S)}{c} \]

Buy repeatedly, each time taking the candidate with the largest delta value, until the budget runs out. The earliest published reference is Gross (1956); Sherbrooke calls it “the increase in system effectiveness per dollar,” and notes that calling it the greedy heuristic is “hardly an improvement.”

It works only if delta values decline as you buy. At one location they do: \(G^{0}\) is nonincreasing, so \(\bar{B}\) is convex, and a sum of convex functions is convex.

Were that not so, a one-step look would undervalue an item whose next two units together are worth more than the first alone, and other items would be bought prematurely.

Two Echelons Break the Convexity

Fix the depot and vary a storeroom: convex. But moving the depot moves every storeroom’s pipeline at once, and across the best splits there is no assurance of convexity.

Units \(S_0\) At storerooms \(\mathit{EBO}\) Reduction
10 10 0 18.6080 0.9967
11 11 0 17.6154 0.9927
12 12 0 16.6303 0.9850
13 9 4 15.6433 0.9870
14 10 4 14.6587 0.9846
⋮
19 15 4 9.9647 0.8842
20 12 8 9.1088 0.8559
21 13 8 8.2462 0.8627

The best split of each total, by VARI-METRIC. Read the Reduction column: where does it rise, and which plan is the bad one?

It rises at 13 and at 21. So totals 12 and 20 lie above the line through their neighbors:

\[ \frac{17.6154 + 15.6433}{2} = 16.6294 < 16.6303 \]

Plan 12 is never worth buying.

Convexification, and Flushout

Convexification. Strike out 12 and 20. The procedure moves from 11 straight to 13 and from 19 straight to 21, buying two at a time and quoting the average of the two reductions as its delta value.

Units bought 10 11 12 13 … 19 20 21
Best \(S_0\) 10 11 12 9 15 12 13

Flushout. The best depot stock falls as the total rises. Going from twelve transformers to thirteen, the depot drops from twelve to nine and four appear at the storerooms. Sherbrooke’s name: depot stock is flushed out to the bases.

Why. A depot unit buys \(G^{0}(S_0)/\lambda_0\) off the delay, shared by four storerooms. While the depot is nearly empty that delay is enormous and pooling dominates; once it is comfortable, a unit does more on the shelf a crew can reach.

The model answers the positioning question as a function of the budget: not “forward stocked?” but “forward stocked at what total investment?”, and not monotonically.

Across Items

Items combine by the same rule, with reductions divided by unit cost. The utility also stocks a voltage regulator: $9,500, 12 failures a year per storeroom, a fifth rebuilt locally in 45 days, depot repair 90 days, shipment 10 days.

Step Bought \(\delta\) per $1,000 Spend \(\mathit{EBO}\), transformer \(\mathit{EBO}\), regulator
1 transformer 0.2632 $3,800 27.6027 11.7041
12 transformer, two 0.2595 $49,400 15.6433 11.7041
19 transformer, two 0.2261 $79,800 8.2462 11.7041
28 transformer 0.1148 $114,000 2.5852 11.7041
29 regulator 0.1053 $123,500 2.5852 10.7042
41 regulator 0.0734 $214,700 1.3122 3.5973

The delta column never rises: that is what convexification bought. Steps 12 and 19 jump the struck-out totals.

No regulator until $114,000 has gone into transformers. The transformer fails nearly four times as often and costs less than half as much, so it removes about a quarter of a backorder per thousand dollars against a tenth.

The Procedure Returns a Curve

allocate(budget, items):
  for each item:
    // Step 1, the two-echelon curve
    for S_0 = 0, 1, 2, ...:
      Wbar <- depot delay at S_0      // VARI-METRIC
      for n = 0, 1, 2, ... at storerooms:
        spread n by marginal analysis
        EBO[S_0][n] <- storeroom backorders
    // Step 2, best split per total; convexify
    curve[T] <- min over S_0 + n = T
    drop every T whose reduction is
         exceeded by the next one
    // Step 3, delta values on what survives
  // Step 4, merge the items by largest delta
  while the next buy fits the budget:
    buy the item whose next delta is largest
  return stock levels, and EBO against cost

Every step of the merge is an efficient plan for the money spent so far, so the output is the whole schedule of backorders against budget.

That is more useful than one plan: a utility can ask whether the step from $114,000 to $123,500 is worth it, which it can answer and the model cannot.

The last buy can overshoot badly if it is an expensive unit. Take the levels reached as minimums and rerun.

The Workbook: the Depot First

Chapter9Models.xlsx, ordered the way the chapter solves: Depot, then Storeroom, then Allocate, plus Ledger.

Depot. One row per unit of pipeline. \(G\) from POISSON.DIST, \(G^{0}\) its complement, \(G^{1}\) the recursion filled down. The fourth column is the one VARI-METRIC adds, the second-moment recursion:

E21:  =$B$13+$B$13^2
E22:  =E21-D22-D21

The stock level is the only decision typed; \(\bar{B}_0\) and \(\mathit{Var}[B_0]\) read out by INDEX.

Storeroom. METRIC closes in one cell, since \(G^{1}(s) = \mu(1 - F(s-1)) - s(1 - F(s))\) for a Poisson.

VARI-METRIC does not: the fitted \(r = 14.3674\) is not an integer and NEGBINOM.DIST truncates it, quietly computing the wrong distribution. The sheet builds the mass function by its own recursion,

\[ g(0) = p^{r}, \qquad g(x) = g(x-1)\,\frac{r+x-1}{x}(1-p) \]

and one cell holds the on-hand identity, which must read zero.

The Two Models on One Screen

The Storeroom sheet at the chapter’s plan. Notice the ratio of the two backorder figures, 1.1875: VARI-METRIC reports about nineteen percent more on a plan neither model changed.

Notice the residual at the bottom, which reads zero to ten places. That is the reason to trust the nineteen percent: both models satisfy the same identity, so the difference is in the tail, not in the bookkeeping.

Allocate and Ledger Sheets

Allocate lays the search flat: one row per total, one column per split. Read the best \(S_0\) column down: it climbs to 11 and drops to 8 at total 12, one unit earlier than the VARI-METRIC table, because the sheet runs METRIC.

The convexity flag looks forward:

M9: =IF(OR(L9="",L10=""),"",
       IF(L10>L9,"drop",""))

Ledger dots the level column with a weeks-held column, =SUMPRODUCT(G5:G23,K5:K23), so the wrong average is harder to write.

Pricing a Repair Contract

The depot shop offers, for a fee, to hold transformer turnaround at 45 days instead of 60. The plan is \(S_0 = 16\), \(S_j = 4\). On Depot, type 45 into B10, one number on a sheet that never mentions a storeroom. What happens to the storerooms?

Cell What it is Before After
Depot!B13 \(\mu_0\) 20.7123 15.5342
Depot!B17 \(\bar{B}_0\) 5.0201 1.3500
Depot!B20 \(\bar{W}\), days 14.54 3.91
Storeroom!B22 \(\mu_j\) 3.2276 2.3101
Storeroom!B34 \(\bar{B}_j\) 0.4815 0.1523

Across four storerooms, 1.9259 falls to 0.6091: 68%. A quarter cut in repair time removed two thirds of the waiting, because the delay divides a backorder level that is itself falling steeply.

The check. \(1.3500/126 = 0.010714\) years, which is 3.91 days, as B20 reports.

What the Same Improvement Costs in Stock

Put 60 back, and buy the reduction instead by raising the depot stock:

Depot!B16 16 18 20 21 22
Depot!B20, days 14.54 9.98 6.30 4.84 3.64
Storeroom!B34 0.4815 0.3280 0.2199 0.1807 0.1501

Six more depot transformers do what the contract does. At the carrying charge of 0.25 a year,

\[ 6 \times 0.25 \times \$3{,}800 = \$5{,}700 \text{ a year} \]

so the contract is worth up to $5,700 a year. A shop asking $4,000 should be taken; one asking $9,000 should be refused and the money spent on stock.

Where should the six go?

Allocate at a total of 38 says 18 at the depot and 5 per storeroom, not 22 and 4. It runs METRIC; judged by VARI-METRIC, 18-and-5 gives 0.6157 against 0.6005, about 2.5% worse, in the direction METRIC’s error predicts.

Designing the Software: the Nouns

Underline the nouns in the requirements and four survive: a storeroom, a depot item (one item’s depot stock and the storerooms it supplies), a model (a set of depot items), and a search, the only thing that chooses.

Three candidates fail, instructively:

  • A depot class. Everything asked of the depot is a property of a distribution. Its stock and its storerooms travel together, so they are one object.
  • METRIC and VARI-METRIC as two classes. They agree on every mean, and two classes would let them drift apart where the chapter says they cannot.
  • A pipeline distribution of our own. The library already has one.
leadTimeDemand = if (depot.forcePoissonAtBases) {
    Poisson(expectedNumInResupply)
} else {
    fitTwoMoments(expectedNumInResupply, varianceNumInResupply)
}

Notice that the two models are a flag, not a type: one object computes the mean, so they cannot disagree about it.

What the Library Supplies

The loss functions. Every location asks its distribution for firstOrderLossFunction, so the single-location measures are written once and answered by whichever family the fit chose.

The second moment, in closed form. A worksheet climbs the recursion because it has rows and no second order loss function. A program has the loss function:

\[ E[B^{2}(s)] = 2\,G^{2}(s) + G^{1}(s) \]

A negative binomial with a fractional \(r\). The library takes \(r = 14.3674\) as a real number, so the fit is a constructor call.

val c = variance / mean
return when {
    c > 1.0 + RATIO_TOLERANCE  -> negativeBinomialOn(mean, variance)
    c >= 1.0 - RATIO_TOLERANCE -> Poisson(mean)
    else -> { val scale = variance / mean; Gamma(mean / scale, scale) }
}

RATIO_TOLERANCE is \(10^{-9}\): rounding, not a model. The third branch exists because nobody has proved the variance always exceeds the mean.

Two Searches, Only One of Them Greedy

The inner search is greedy and exact. At a fixed depot stock the storerooms are convex, so handing out units one at a time to whichever gains most cannot be improved on.

The outer step is a minimum, the best depot level per total, and that is where convexity is lost.

Convexification is a lower convex hull, reached by jumping to whichever later total gives the steepest descent:

var slopeMax = 0.0
for (c in kIndex + 1 until maxRows) {
    val s = slope(kIndex, c)
    if (s >= slopeMax) { slopeMax = s; kLast = c }
}

The totals it skips are the ones struck out by hand, and the delta value is computed across the jump.

Pricing the Budget Instead of Enforcing It

Let \(\theta\) represent a charge per dollar held, and minimize

\[ w(\theta) = \sum_j \bar{B}_j(S_j) + \theta\Big(c_0S_0 + \sum_j c_jS_j\Big) \]

At a fixed \(\theta\) the storerooms no longer compete, and each solves a newsvendor: buy while the chance of needing the next unit exceeds its price,

\[ S_j = \min\left\{S : G(S) \ge 1 - \theta c_j\right\} \]

The depot still needs a search, because moving it moves every storeroom.

The multiplier’s scale is set by the unit cost

A storeroom stocks nothing once \(\theta \ge 1/c_j\), so the useful range is \((0, 1/c_j)\): for a $3,800 transformer, \(2.6 \times 10^{-4}\). Search far above it and the algorithm reports, correctly and uselessly, that no root exists.

Three Searches, Two to One

Both items, a budget of $250,000:

Search Spend Storeroom backorders Depot, transformer Inside budget
Marginal analysis $247,000 2.8792 19 yes
Lagrangian, bisection $247,000 2.8792 19 yes
Lagrangian, enumeration $250,800 2.6840 20 no, by $800

Stock levels are integers, so cost is a step function of \(\theta\): at \(5.1356 \times 10^{-5}\) the plan costs $250,800, at \(5.1361 \times 10^{-5}\) it costs $247,000. No multiplier spends exactly $250,000, so a search must choose a side.

Bisection returns the side that satisfies the constraint. Enumeration keeps the smallest absolute gap, and $800 over is closer than $3,000 under.

A planner who must not overspend wants bisection or marginal analysis. One asking what the budget nearly buys learns from the enumeration that $800 more removes another 0.2 backorders. Never read the enumeration’s answer as respecting the budget.

Running the Chapter’s Examples

val item = VMItem(1, 16, 3800.0, days(60.0))
repeat(4) { item.addBaseItem(45.0, days(30.0), 0.3, days(10.0), 4, 3800.0) }
  METRIC       mu_j   3.2276  var   3.2276  Bbar_j   0.4055  Ibar_j   1.1778  system   1.6218
  VARI-METRIC  mu_j   3.2276  var   3.9527  Bbar_j   0.4815  Ibar_j   1.2539  system   1.9259
  total        EBO    S_0  reduction    kept?
     11    17.6154     11     0.9927
     12    16.6303     12     0.9850  dropped
     13    15.6433      9     0.9870
     ...
     20     9.1088     12     0.8559  dropped
     21     8.2462     13     0.8627

The network is built depot first, with times in days at the call site so the conversion is visible. Notice that mu_j agrees to four decimals and var does not: no mean changes, enforced because one object produced both. The depot column falls from 12 to 9 at total 13 and from 15 to 12 at total 20: flushout and non-convexity are the same event seen from two columns.

What We Did Today, and in This Chapter

Marginal analysis buys by delta value, \(G^{0}(S)/c\), and needs convexity.

Two echelons break it. Convexification strikes out totals 12 and 20, and the depot’s stock falls as the budget rises: flushout, the positioning answer as a function of money.

Across items, the transformer is bought first for $114,000, on arithmetic, not unit price.

The sheets price a contract: six depot units, $5,700 a year, is what a 45-day turnaround is worth.

The software keeps one class for two models and offers searches that differ in which side of the budget they land.

The chapter in one line. The depot’s wait couples the levels; Palm, Little and a second moment compute it; marginal analysis spends against it.

For Next Time

Read before next session: the opening of Multi-Echelon Systems with Batch Ordering, What Batching Changes and The Item and the Network.

Today’s material was Spending a Budget Across Items, Building These Models in a Worksheet and Designing the Software.

Next session:

  • What changes when a location orders in batches instead of one for one
  • A hub that batches, and why the stream it sends up is no longer Poisson

Every simplification of this chapter rested on \(Q = 1\). Next chapter gives it up.

⌂ Index