Distributing Distributions


A Normal Distribution Object

In this example, we expose a Normal distribution as a COM object. This class provides methods for
  • generating samples
  • computing percentiles
  • computing quantiles
  • computing densitys
  • shifting and scaling the distribution for subsequent computations
Unlike the S functions to which one must supply the parameters of the distribution, objects from this class maintain state and the methods have access to these. To do this, we generate a closure containing simple functions that merely call the regular S functions to for dealing with the Normal distribution. These are rnorm, pnorm, qnorm, dnorm.

Because the Normal distribution object has state given by the mean and standard deviation, we need a closure in R to "capture" this state. We do this by providing a generator function that defines the methods with these settings.

g <- function(mu = 0, sigma = 1) 
{
  generic <- function(n, abc=10, k="My string") {
    n + 10
  }

  sample <- function(n) {
     rnorm(as.integer(n), mu, sigma)
  }

  percentile <- function(q, lower = TRUE) {
    pnorm(as.numeric(q), mu, sigma, lower.tail = as.logical(lower))
  }

  quantile <- function(p) {
    qnorm(as.numeric(p), mu, sigma)
  }

  density <- function(x) {
     dnorm(as.numeric(x), mu, sigma)
  }

  deviate <- function() {
    rnorm(1, mu, sigma)
  }

  list(sample = sample, percentile = percentile,
       quantile = quantile, density = density,
       deviate = deviate,
       generic = generic,
       .properties = c("mu", "sigma"),
       .help = c(sample = "generate a sample of values",
                percentile = "CDF values from this distribution",
                quantile = "quantile values from this distribution",
                density = "values of the density function for this distribution"
                ))
}

Now we register this class definition with R and for clients to access.
def = SCOMIDispatch(g, "SNormal")
def@classId = getuuid("c484d2f9-21f5-49ac-8c8d-2007e12245d3")
registerCOMClass(def)

The Client

We can use this class in any of the COM supported classes. For example, consider Visual Basic (VB). We first create an instance of this class. We declare some variables and then create the object.
 Dim N as Object
 Dim v as Variant
 
 Set N = CreateObject("SNormal")
Now we can invoke the objects methods. So we create a sample of 3 elements.
 v = N.sample(3)
Now v is a VARIANT. Unlike high-level languages such as Python or Perl, Visual Basic doesn't convert the array returned from R directly into a VB array. Instead, we can access it via the variant and ask for its upper and lower indices and query its contents.
   Debug.Print TypeName(v)
   Debug.Print UBound(v)
   Debug.Print LBound(v)
   Debug.Print v(1)
We can iterate over its entries as follows
   For i = LBound(v) To UBound(v)
      Debug.Print v(i)
   Next i