[Rcpp-devel] Organization of C++ classes for glm families
Douglas Bates
bates at stat.wisc.edu
Tue Mar 16 21:11:31 CET 2010
On Tue, Mar 16, 2010 at 3:01 PM, Douglas Bates <bates at stat.wisc.edu> wrote:
> On Tue, Mar 16, 2010 at 2:00 PM, Douglas Bates <bates at stat.wisc.edu> wrote:
>> In profiling some of the code for generalized linear mixed models I
>> discovered that a considerable amount of the time was being taken up
>> in evaluation of some of the functions in the glm family. Many of
>> these functions in the family are candidates for a std::transform
>> application
>>
>>> str(poisson())
>> List of 12
>> $ family : chr "poisson"
>> $ link : chr "log"
>> $ linkfun :function (mu)
>> $ linkinv :function (eta)
>> $ variance :function (mu)
>> $ dev.resids:function (y, mu, wt)
>> $ aic :function (y, n, mu, wt, dev)
>> $ mu.eta :function (eta)
>> $ initialize: expression({ ...
>> $ validmu :function (mu)
>> $ valideta :function (eta)
>> $ simulate :function (object, nsim)
>> - attr(*, "class")= chr "family"
>>
>> In most cases the time is taken in linkinv, variance and mu.eta.
>>
>> I do have one implementation of glm families in C++ in the lme4a
>> package from the lme4 project on R-forge but that implementation is
>> based on a complex set of concrete classes using virtual functions and
>> doesn't take advantage of containers like std::vector or
>> Rcpp::NumericVector.
>>
>> I think a more idiomatic C++ implementation would use containers and
>> the std::transform algorithm. The characteristics like the linkfun,
>> linkinv and mu.eta functions are associated with the link name ("log"
>> in the example above).
>>
>> Would it be feasible to associate the scalar transformation function,
>> in this case it would be the log function from the math library but in
>> other cases it could be like
>>
>> double inverseLink(double x) {return 1/x;}
>>
>> with the name of the link. I would think of using a std::map for that
>> but I don't know what the class or type of the "value" slot would be.
>> Some exploration indicates that it may be a struct that is derived
>> from the std::unary_function<double, double> but right now my head is
>> beginning to hurt reading documentation. Could someone give me an
>> example of how I would use, say, the exp or the log function in a
>> std::transform?
>>
>> The second level would be to associate the scalar transformation
>> function with the name, say in a std::map but first I need to make
>> std::transform work with a scalar function.
>
> To follow up on my own posting, the things I have tried are various versions on
>
> cpp <- '
> Rcpp::NumericVector xv(x);
> Rcpp::NumericVector y(xv.size());
> std::transform(xv.begin(), y.begin(), ll);
> return y;
> '
> ff <- cfunction(signature(x = "numeric"), cpp, Rcpp = TRUE, verbose = FALSE,
> otherdefs = "double ll(const double xx){return log(xx);}",
> includes = "#include <cmath>")
>
> which always produces an error of the form
>
> :14: error: no matching function for call to ‘transform(double*,
> double*, double (&)(double))’
>
> I'm at the point one often gets to with a new language that my code
> will not compile and I have no idea of how to fix it.
OK, it was a dumb mistake. I misread the documentation. If I change
the code to
cpp <- '
Rcpp::NumericVector xv(x);
Rcpp::NumericVector y(xv.size());
std::transform(xv.begin(), xv.end(), y.begin(), ll);
return y;
'
ff <- cfunction(signature(x = "numeric"), cpp, Rcpp = TRUE, verbose = FALSE,
otherdefs = "static inline double ll(double xx){return
log(xx);}",
includes = "#include <cmath>")
it's happy. Now on to that question about std::map<std::string,
std::unary_function<double, double>>
More information about the Rcpp-devel
mailing list