Library

Newsvendor Model

NewsvendorModel.NVModelType
NVModel(demand, cost, price, salvage=0)

Captures a Newsvendor model with unit cost, unit selling price, and demand distribution. The demand can be any univariate distribution from the package Distributions.jl.

Examples

julia> using Distributions
julia> nvm = NVModel(demand = Normal(50, 20), cost = 5, price = 7)
Data of the Newsvendor Model
 * Demand distribution: Normal{Float64}(μ=50.0, σ=20.0)
 * Unit cost: 5.00
 * Unit selling price: 7.00

This defines a model with unit cost 5 and unit price 7, where uncertain demand draws from a normal distribution with mean 50 and standard deviation 20.

Optional keyword arguments and their defaults:

NVModel(demand [; kwargs])
  • cost for a unit; defaults to 0.0
  • price for selling a unit; defaults to 0.0
  • salvage value obtained from scraping a leftover unit; defaults to 0.0
  • holding cost induced by a leftover unit, e.g., extra captial cost or warehousing cost; essentially a negative salvage value; defaults to 0.0
  • backorder penalty for being short a unit, e.g., contractual penalty for missing delivery targets or missed future profit of an unserved customer; defaults to 0.0
  • substitute benefit received from selling an alternative to an unserved customer, e.g., when selling another product or serving in the future; essentially a negative backorder penalty; defaults to 0.0
  • fixcost fixed cost of operations; defaults to 0.0
  • q_min minimal feasible quantity, e.g., due to production limits; must be nonnegative; defaults to 0
  • q_max maximal feasible quantity, e.g., due to production limits; must be greater than or equal to q_min; defaults to Inf

Examples

Define a newsvendor problem with unit cost 5, unit price 7, uniform demand between 50 and 80, where a unit salvages for 0.5, and backorder comes at a penalty of 2 per unit, and the operations incur a fixed cost of 100, as follows:

julia> nvm2 = NVModel(demand = Uniform(50, 80), cost = 5, price = 7, salvage = 0.5, backorder = 2, fixcost = 100)
Data of the Newsvendor Model
 * Demand distribution: Uniform{Float64}(a=50.0, b=80.0)
 * Unit cost: 5.00
 * Unit selling price: 7.00
 * Unit salvage value: 0.50
 * Unit backorder penalty: 2.00
 * Fixed cost: 100.00

Note that demand is a necessary argument that can be passed without keyword in first place. Moreover, only values that differ from the default will be shown.

Define a newsvendor problem with unit cost 5, unit price 7, uniform demand between 50 and 80, where a unit salvages for 0.5, and backorder comes at a penalty of 2 per unit, and the operations incur a fixed cost of 100, as follows:

julia> nvm3 = NVModel(Uniform(50, 80), 5, 7, 0.5, backorder = 2, fixcost = 100, q_min=0)
Data of the Newsvendor Model
 * Demand distribution: Uniform{Float64}(a=50.0, b=80.0)
 * Unit cost: 5.00
 * Unit selling price: 7.00
 * Unit salvage value: 0.50
 * Unit backorder penalty: 2.00
 * Fixed cost: 100.00
julia> nvm3 == nvm2
true

Holding cost is essentially overage cost. Backorder penalty is essentially underage cost. The beer game has holding cost of 0.5 USD and backlog costs 1 USD per unit. Demand is assumed to be uniform betwen 0 and 300.

julia> beer = NVModel(Uniform(0, 300), backorder = 1, holding = 0.5)
Data of the Newsvendor Model
 * Demand distribution: Uniform{Float64}(a=0.0, b=300.0)
 * Unit cost: 0.00
 * Unit selling price: 0.00
 * Unit holding cost: 0.50
 * Unit backorder penalty: 1.00
source

Optimizing expected profit

NewsvendorModel.solveFunction
solve(nvm::NVModel [; rounded = true])

Compute the stocking quantity q_opt(nvm) that maximizes the expected profit as well as further the metrics when using it. The optimal quantity is rounded up to the next integer by default. To get the exact real number, set the keyword arguement rounded = false.

source

Quantities

NewsvendorModel.q_optFunction
q_opt(anp::AbstractNewsvendorProblem; rounded = true)

Compute the quanitity that maximizes expected profit for a newsvendor problem (i.e., where critical fractile equals in-stock probability). Attempts to solve

\[F(q_{opt}) = \textrm{critical fractile} \]

where F is the c.d.f. of the demand distribution. Returns closest next integer unless rounded=false; then, it returns exact real. Clamps at qmin and qmax.

source
q_opt(res::NVResult)

Get optimal quantity from a stored result.

source
NewsvendorModel.q_scarfFunction
q_scarf(anp::AbstractNewsvendorProblem)

Compute the quanitity that maximizes the minimal expected profit among all distributions with the same mean and variance. Worst-case solution (Scarf, 1958)

\[q_{scarf} = \mu + \sigma/2 * (\sqrt{r} - \sqrt{1/r})\]

where

\[r = \frac{\textrm{underage cost}}{ \textrm{overage cost}}\]

source

Metrics

NewsvendorModel.critical_fractileFunction
critical_fractile(anp::AbstractNewsvendorProblem)

Compute the critical fractile for a newsvendor problem:

\[\textrm{critical fractile} = \frac{\textrm{underage cost}}{\textrm{underage cost} + \textrm{overage cost}}\]

source
critical_fractile(res::NVResult)

Get critical fractile from a stored result.

source
NewsvendorModel.profitFunction
profit(anp::AbstractNewsvendorProblem)

Compute expected profit when stocking quantity q_opt.

profit(anp::AbstractNewsvendorProblem, q)

Compute expected profit when stocking quantity q. It is given by

\[E[\textrm{profit}] = \textrm{underage cost} \times \mu - E[\textrm{mismatch cost}] + \textrm{profit shift}\]

source
profit(res::NVResult)

Get expected profit from a stored result.

source
NewsvendorModel.mismatch_costFunction
mismatch_cost(anp::AbstractNewsvendorProblem, q)

Compute expected mismatch cost when stocking quantity q. It is given by

\[E[\textrm{mismatch cost}] = \textrm{underage cost} \times E[\textrm{lost sales}] + \textrm{overage cost} \times E[\textrm{leftover}]\]

source
NewsvendorModel.lost_salesFunction
lost_sales(anp::AbstractNewsvendorProblem, q)

Compute expected lost sales when stocking quantity q.

source
lost_sales(res::NVResult)

Get expected lost sales model from a stored result.

source
NewsvendorModel.salesFunction
sales(anp::AbstractNewsvendorProblem, q)

Compute expected sales when stocking quantity q.

source
sales(res::NVResult)

Get expected sales from a stored result.

source
NewsvendorModel.leftoverFunction
leftover(anp::AbstractNewsvendorProblem, q)

Compute expected leftover inventory when stocking quantity q.

\[E[\textrm{leftover}] = \int_{-\infty}0^q(q - x)f(x)dx \]

source
leftover(res::NVResult)

Get expected leftover from a stored result.

source

AbstractNewsvendorProblem

NewsvendorModel.AbstractNewsvendorProblemType

An abstract newsvendor problem is essentially described by having a

  • demand distribution,
  • cost of overage,
  • cost of underage, and
  • profit_shift term.

Its standard concrete type might come as a NewsvendorModel, defined by unit cost, uni selling price etc.

source

Required functions that determine a newsvendor problem

NewsvendorModel.profit_shiftMethod

profit_shift(anp::AbstractNewsvendorProblem)

Define how profit is shifted because of fixed cost, penalty, etc.; defautls to 0.0.

source