The previous tutorial introduced S3 and piping into distr6, allowing different approaches to calling R6 methods. In this tutorial we take a look at a big feature of distr6, decorators.

Note: Decorators in distr6 are still maturing, this means the API is still subject to minor changes and the internal computations may be improved, therefore we are aware performance may be sub-optimal.

In object-oriented programming it is common to discuss ‘Design Patterns’ as specific methods used to solve coding problems, decorators are one of these ‘patterns’. For full definitions and details about design patterns, we refer the reader to the seminal Design Patterns textbook (Gamma et al. 1994). Briefly, the decorator design pattern is used to add functionality to an object. For example, say we have a class that only has a `print`

method and a decorator for `summary`

methods. Then the user can either use the object by itself with the `print`

method only or optionally you can ‘decorate’ the object and thereby use the `summary`

method. This is perhaps confusing in the abstract, so lets work through an example in distr6. We will go through a quick example and then return to which decorators are available and how they are used in distr6:

N <- Normal$new() N$survival(1) #> Error in eval(expr, envir, enclos): attempt to apply non-function decorate(N, "ExoticStatistics") #> Normal is now decorated with ExoticStatistics #> Norm(mean = 0, var = 1, sd = 1, prec = 1) N$survival(1) #> [1] 0.1586553

In the example above we:

- Constructed a Normal distribution
- Demonstrated that the
`survival`

method does not exist - Decorated the distribution with the
`ExoticStatistics`

decorator - Successfully evaluated the survival function

The CoreStatistics decorator includes methods for numeric calculations, a generalised moments `kthmoment`

function and a generalised expectation method `genExp`

. All methods can be viewed using `?CoreStatistics`

. In distr6 we have a strict design principle that only analytic results should be provided as methods in distributions, i.e. we only return results for which we know the output is 100% accurate. The `CoreStatistics`

decorator allows you to return numeric results when analytic ones aren’t available. For example,

w <- Weibull$new() # Error as the characteristic function doesn't exist w$cf(1) #> Error in eval(expr, envir, enclos): attempt to apply non-function decorate(w, "CoreStatistics") #> Weibull is now decorated with CoreStatistics #> Weibull(shape = 1, scale = 1, altscale = 1) # Warning as numerical integration used w$cf(5) #> Results from numeric calculations are approximate only. Better results may be available. #> Results from numeric calculations are approximate only. Better results may be available. #> [1] 0.0384616+0.1923076i

The decorator also introduces generalised moment and expectation methods. The help documentation for these `?kthmoment`

and `?genExp`

give a full overview to these methods, but both are very useful for modelling, inference and deriving other numeric results.

The ExoticStatistics decorator includes more complex numeric methods as well as survival, hazard and cumulative hazard that may or may not be analytic expressions (depending what is available in the distribution object). Once again all the methods added by this decorator can be viewed using `?ExoticStatistics`

. For example,

N <- Normal$new() # Error as the characteristic function doesn't exist N$hazard(1) #> Error in eval(expr, envir, enclos): attempt to apply non-function decorate(N, "ExoticStatistics") #> Normal is now decorated with ExoticStatistics #> Norm(mean = 0, var = 1, sd = 1, prec = 1) # No warning as an analytic expression using pdf and cdf are used N$hazard(1) #> [1] 1.525135 # Warning as numeric calculations are used N$pdfPNorm(2,0,4) #> Results from numeric calculations are approximate only. Better results may be available. #> [1] 0.3755628

The final implemented decorator is used to impute missing d/p/q/r methods. We will return to the `FunctionImputation`

decorator in a future tutorial which looks at constructing custom distributions.

There are two main ways to decorate distributions in distr6, either in construction or after construction. We show these by example:

In Construction

Normal$new(decorators = "CoreStatistics") #> Norm(mean = 0, var = 1, sd = 1, prec = 1) Normal$new(decorators = c("CoreStatistics", "ExoticStatistics")) #> Norm(mean = 0, var = 1, sd = 1, prec = 1)

After Construction

N <- Normal$new() decorate(N, "CoreStatistics") #> Normal is now decorated with CoreStatistics #> Norm(mean = 0, var = 1, sd = 1, prec = 1) # Or piping as in the last tutorial library(magrittr) Normal$new() %>% decorate(c("CoreStatistics", "ExoticStatistics")) #> Normal is now decorated with CoreStatistics, ExoticStatistics #> Norm(mean = 0, var = 1, sd = 1, prec = 1)

And that’s all there is to it! If you forget which decorators are available, just run `listDecorators()`

, or `listDecorators(simplify = FALSE)`

if you want to see which methods they include at the same time.

In this tutorial we looked at decorators in distr6 to obtain numeric results, methods for statistical modelling and imputation methods for missing d/p/q/r functions. In the next tutorial we look at the next big feature in distr6, wrappers.