Using this function, two distributions, given as ddf objects, can be
convolved.
Source
Under the hood, this functions uses a C++ implementation for calculating
the convolution in order to get significant performance gains, compare
convolve_cpp().
Details
In general, given two functions \(f\) and \(g\) defined on the set \(\mathbb{Z}\) of integers, the discrete convolution of \(f\) and \(g\) is given by $$(f \ast g)(n) = \sum_{m=-\infty}^{\infty} f(n-m) g(m).$$ Note how the sum on the right hand side ranges over all products where the arguments of \(f\) and \(g\) are integers \(k,l\in\mathbb{Z}\) such that \(k+l=n\).
This implementation of the convolution uses this last observation as its basis which makes it possible to also calculate the convolution if the domains are not (subsets of) \(\mathbb{Z}\) (but of course still discrete).
For a stochastic interpretation of the convolution, recall that given two
independent random variables \(X\) and \(Y\) with probability mass
functions \(p_X\) and \(p_Y\), the sum \(X + Y\) has probability mass
function \(p_X \ast p_Y\).
Hence, convolving two ddf distributions gives the distribution corresponding
to their sum.
See also
Other convolution functions:
conv_n(),
convolve_cpp()
Examples
# Calculate the distribution of the sum of throwing a dice twice
dice <- ddf(1:6)
conv(dice, dice, desc = "Distribution of throwing a dice twice")
#> Distribution of throwing a dice twice
#>
#> Support:
#> [1] 2 3 4 5 6 7 8 9 10 11 12
#>
#> Probabilities:
#> [1] 0.02777778 0.05555556 0.08333333 0.11111111 0.13888889 0.16666667
#> [7] 0.13888889 0.11111111 0.08333333 0.05555556 0.02777778
# (Up to description) equivalent call using generic method
dice * dice
#> A convolution
#>
#> Support:
#> [1] 2 3 4 5 6 7 8 9 10 11 12
#>
#> Probabilities:
#> [1] 0.02777778 0.05555556 0.08333333 0.11111111 0.13888889 0.16666667
#> [7] 0.13888889 0.11111111 0.08333333 0.05555556 0.02777778
# Note that for distributions which are approximated without
# also being normalized, approximation errors can propagate
# when convolving:
try(conv(unif(5), geometric(0.9, normalize = FALSE)))
#> Error in h(simpleError(msg, call)) :
#> error in evaluating the argument 'dist' in selecting a method for function 'supp': invalid class “ddf” object: probabilities have to sum up to approximately 1
# This can be corrected by using a better approximation
conv(unif(5), geometric(0.9, eps = 1e-11, normalize = FALSE))
#> A convolution
#>
#> Support:
#> [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#>
#> Probabilities:
#> [1] 1.80000e-01 1.98000e-01 1.99800e-01 1.99980e-01 1.99998e-01 1.99998e-02
#> [7] 1.99998e-03 1.99998e-04 1.99998e-05 1.99998e-06 1.99998e-07 1.99980e-08
#> [13] 1.99800e-09 1.98000e-10 1.80000e-11
# Or simply by normalizing
conv(unif(5), geometric(0.9))
#> A convolution
#>
#> Support:
#> [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14
#>
#> Probabilities:
#> [1] 1.80000e-01 1.98000e-01 1.99800e-01 1.99980e-01 1.99998e-01 1.99998e-02
#> [7] 1.99998e-03 1.99998e-04 1.99998e-05 1.99998e-06 1.99980e-07 1.99800e-08
#> [13] 1.98000e-09 1.80000e-10
# When one is interested in the difference instead of
# the sum, one can use the generic `-` which multiplies
# the support of a distribution with -1
conv(unif(6), -unif(6))
#> A convolution
#>
#> Support:
#> [1] -5 -4 -3 -2 -1 0 1 2 3 4 5
#>
#> Probabilities:
#> [1] 0.02777778 0.05555556 0.08333333 0.11111111 0.13888889 0.16666667
#> [7] 0.13888889 0.11111111 0.08333333 0.05555556 0.02777778
