- 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

For example, the fill rate had to be computed with:

Grid.Q = Grid.Max - Grid.Min + 1 Grid.Tau1 = cumsum(Grid.Probability, -Grid.Max, Id) EX = sum(Grid.Probability * (Grid.Max + Grid.Min) / 2) P = sum(Grid.Probability) Grid.Y = Grid.Min == 0 ? 0 : \ (Grid.Tau1 * Grid.Q - Grid.Probability * (Grid.Q-1) / 2) / EX Grid.FillRate = cumsum(Grid.Y, Grid.Max, Id) * P

which, using algebra of distribution, simply becomes:

Demand = distrib(Id, Grid.Probability, Grid.Min, Grid.Max) FillRate = fillrate(Demand)

Obviously, having a special

`fillrate()`

function certainly does help make the code a lot more compact and readable, but, in practice, nearly all calculations performed on the grid itself tend to be cryptic. In contrast, distributions offer a way to perform the same calculation (and even more actually) with much less hassle; making the script not only faster, but much more reliable.Also, Envision distributions (referred as

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.

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

`X`

and `Y`

are distribution vectors, the same operation is similarly 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 to combine numbers and distributions - but only if the resulting distribution is compact.

Z = 2 * X // OK, it's compact Z = X / 2 // not dividing by zero is OK Z = X + 1 // incorrect, not a compact distribution Z = X / Y // incorrect, Y is compact hence has zero valuesThe 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, Grid.Probability, Grid.Min, Grid.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)`

.`extend.distrib()`

function which precisely does this. The syntax is illustrated as follows:
X = poisson(1) table Grid = extend.distrib(X) show table "My Grid" with Id, Grid.Min, Grid.Max, Grid.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 `Grid`

. This table has an affinity `(Id, *)`

, and as illustrated on line 3, the table is auto-populated with the numeric columns `Grid.Min`

, `Grid.Max`

and `Grid.Probability`

. Both `Grid.Min`

and `Grid.Max`

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

`Grid.Min`

and `Grid.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 `Grid.Min`

and `Grid.Max`

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

`extend.distrib()`

offers the first overload:
table Grid = 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 Grid = 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.`dirac(n)`

returns a function zero valued everywhere except for`n`

where the function is valued at 1.`identity(n)`

returns the function $\text{id}: k \to k$ but limited to the segment [0;n] and 0 elsewhere.`uniform(n)`

returns the function $\text{unif}: k \to 1$ but limited to the segment [0;n] and 0 elsewhere.`uniform(m, n)`

returns the function $\text{unif}: k \to 1$ but limited to the segment [m;n] and 0 elsewhere.`uniform(D)`

returns the function $\text{unif}: k \to 1$ but limited to the positive support of the distribution`D`

and 0 elsewhere.`poisson(a)`

returns the Poisson distribution of parameter`a`

($\lambda$ in literature).`exponential(a)`

returns the exponential distribution of parameter`a`

($\lambda$ in literature).

`crps(X, A)`

where`A`

are integral numbers, returns the Continuous Ranked Probability Score (CRPS).`mean(X)`

returns the statistical mean.`variance(X)`

returns the statistical variance.`mass(X)`

returns to mass of distribution, that is, $\sum_{k=-\infty}^{\infty}f(k)$`isranvar(X)`

returns a Boolean that is`true`

if the distribution is a random variable.`int(X, A, B)`

where`A`

and`B`

are integral numbers returns the integral of`X`

over the inclusive segment [A;B].`quantile(X, tau)`

returns the quantile of the distribution; the smallest $x$ such as $\mathbf{P}[X \leq x] \geq \tau$.`spark(X)`

returns a text value that contains compact ascii-art representation of the distribution.

`reflect(X)`

returns the reflected distribution $k \to f(-k)$.`transform(X,a)`

returns a distribution that approximates through interpolation $k \to f(k / a)$.`fillrate(X)`

returns the marginal fill rate. Expects a random variable as input and returns a random variable.`truncate(X, a, b)`

returns the truncated distribution $k \to f(k) \text{ if } k \in [a; b] \text{ else } 0$. The boundaries`A`

and`B`

are inclusive.`maxr(X, a)`

returns the distribution $k \to f(k) \text{ if } k \in ]-\infty; a - 1] \text{ or } \sum_{i=a}^\infty f(i) \text{ if } k = a \text{ else } 0$.`minr(X, a)`

returns the distribution $k \to f(k) \text{ if } k \in [a + 1; \infty[ \text{ or } \sum_{i=-\infty}^a f(i) \text{ if } k = a \text{ else } 0$.

`*`

, namely:
Z = X +* Y // additive convolution Z = X -* Y // substractive convolution, same as X +* reflect(Y) Z = X ** Y // multiplicative convolution Z = X ^* Y // convolution powerThe 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.

See also our page on convolution power.