- The Quantitative Supply Chain Manifesto
- The Lokad test of supply chain performance
- An overview of quantitative supply chain
- Generalized probabilistic forecasting
- Decision-driven optimization
- Economic drivers
- Data preparation
- The Supply Chain Scientist
- Timeline of a typical project
- Project deliverables
- Assessing success
- Antipatterns in supply chain

- Inventory forecasting
- Prioritized ordering report
- Old forecasting input file format
- Old forecasting output file format
- Choosing the service levels
- Managing your inventory settings
- The old Excel forecast report
- Using tags to improve accuracy
- Oddities in classic forecasts
- Oddities in quantile forecasts
- Stock-out's bias on quantile forecasts
- Daily, weekly and monthly aggregations

Home » Resources » Here

Mathematical distributions are powerful and useful for modelling many business situations, especially those where uncertainty exists. Envision treats

Within Envision, distributions are materialized through a special data type named

d := dirac(42)

Distributions can be exported into a file using the Ionic data files. However, distributions cannot be exported

Envision offers many more ways to generate distributions. They will be reviewed in the following sections.

This plot has been generated in Envision with the single-liner detailed below:

show histogram "My first distribution!" tomato with poisson(21)The

`histogram`

tile expects a single scalar distribution to be provided after the `with`

keyword.$$f+g: k \to f(k) + g(k)$$ From Envision's perspective, assuming that both

`X`

and `Y`

are distribution vectors, the same operation can similarly be written as:
Z = X + YIt must be noted that even when dealing with distributions, Envision remains a

Z := X + YIn this and the following sections, whenever we use

`X`

and `Y`

in script examples, we assume that these two variables are actual distributions.Then, the point-wise multiplication and subtraction are defined with: $$f \times g: k \to f(k) \times g(k)$$ $$f-g: k \to f(k)-g(k)$$ which translates quite transparently into the following Envision syntax:

Z = X * Y Z = Z - YFrom the perspective that a number $\alpha$ can be implicitly assimilated to a constant function $f_{\alpha}: k \to \alpha$, Envision allows you to combine numbers and distributions - but only if the resulting distribution is compact.

// OK, it's compact Z = 2 * X // not dividing by zero is OK Z = X / 2 // incorrect, not a compact distribution Z = X + 1 // incorrect, Y is compact hence has zero values Z = X / YThe distributions can also be shifted. The shift operator is typically written as:

$$f_{n}: k \to f(k+n)$$ The corresponding Envision syntax is:

Z = X << n // left shift Z = X >> n // right shiftNaturally, if

`n`

is negative, then the shift operators keep working, but the left shift becomes a right shift, and `distrib()`

function. The relevant syntax is:
Demand = distrib(Id, G.Probability, G.Min, G.Max)The resulting

`Demand`

variable is a distribution. When the original grid includes segments that are longer than 1, `distrib()`

uniformly spreads the mass across the segment. The mass of the distribution is preserved by the `distrib()`

function. (*) The serialization of a distribution is the process of turning the distribution data into a regular tabular format which can be stored as a flat file. In order to handle the distribution as an actual distribution - and not as a table - we need to de-serialize the table first. This is exactly what is being done above with the

`distrib()`

function.In addition, Envision also offers the possibility to generate a distribution directly from a set of observed numeric values. This is the purpose of the

`ranvar()`

aggregator:
X = ranvar(Orders.Quantity)The

`ranvar()`

aggregator returns a `ranvar()`

returns `dirac(0)`

.Finally, it is possible to generate a distribution from a

`ranvar.segment()`

aggregator.
D = ranvar.segment( // first date for a each item start: Items.Start // last date (inclusive) for each item end: Items.End // length of period for each item horizon: Items.Horizon // integer for skipping elements step: Items.Step // the date of each event date: Orders.Date // the quantity of each event quantity: Orders.Quantity)It computes, for each item, the distribution of the sum of event quantities for periods of horizon length entirely between the first and last date for that item. Typically, the horizon length would be the leadtime of an item.

`extend.distrib()`

function which does precisely this. The syntax is illustrated as follows:
X = poisson(1) table G = extend.distrib(X) G.Probability = int(X, G.Min, G.Max) show table "My Grid" with Id G.Min G.Max G.Probabilitywhere

`X`

is the distribution vector generated on line 1 as a Poisson distribution. On line 2, the distributions are inflated into a table named `G`

(for `(Id, *)`

, and as illustrated on lines 3 to 7, the table is auto-populated with the numeric columns `G.Min`

and `G.Max`

. Both `G.Min`

and `G.Max`

are inclusive boundaries.When extending relatively compact distributions, the resulting table typically contains lines of +1 increments - aka

`G.Min`

and `G.Max`

increased by +1 from one line to the next. However, if we were to consider the extension of high valued distributions, for example `dirac(1000000)`

, then it would be extremely inefficient to generate millions of lines. Thus, the function `extend.distrib()`

will aggregate large distributions into thicker buckets. This explains why we have both `G.Min`

and `G.Max`

, which represent the inclusive boundaries of the bucket.In order to gain more control over the granularity of the buckets generated, the function

`extend.distrib()`

offers the first overload:
table G = extend.distrib(X, S)where

`S`

is a number vector. The resulting table provides buckets aligned with the segments [0;0] [1;S] [S+1; S+M] [S+M+1;S+2*M] ... where `M`

is the default bucket size - also called the Finally, the second overload of

`extend.distrib()`

provides even more control with:
table G = extend.distrib(X, S, M)where

`M`

is a mandatory bucket size. If `M`

is zero, then the extension reverts the default bucket size, auto-adjusted by Envision. This second overload is particularly useful when Beware that

`extend.distrib(X, S, M)`

may fail depending on the capacity allocated to your Lokad account if you try to extend a high valued distribution while forcing a low multiplier.`*`

, namely:
// additive convolution Z = X +* Y // subtractive convolution, same as X +* reflect(Y) Z = X -* Y // multiplicative convolution Z = X ** Y // convolution power Z = X ^* YThe additive (resp. the substractive) convolution can be interpreted as the sum (resp. the difference) of the two independent random variables $X+Y$ (resp. $X-Y$). The multiplicative convolution, also known as the Dirichlet convolution, can be interpreted as the product of two independent random variables.

The convolution power is more complex and represents: $$X ^ Y = \sum_{k=0}^{\infty} X^k \mathbf{P}[Y=k] \text{ where } X^k = X + \dots + X \text{ ($k$ times)}$$ This last operation is of interest because of its relationship to the process leading to an integrated demand forecast, where $X$ represents the daily demand - assumed stationary - and where $Y$ represents the probabilistic lead times.

The