[Rcpp-devel] calling R function triggers tryCatch() ???

Romain Francois romain at r-enthusiasts.com
Thu Oct 3 13:14:56 CEST 2013


Le 03/10/13 13:03, Thomas Tse a écrit :
> Hi,
>
> I'm trying to implement a faster version of apply(x, 1L, FUN) in C++ but
> found some strange behaviors.
>
> // [[Rcpp::export]]
> NumericVector rowApply(NumericMatrix& x, const Function& FUN)
> {
>    int n = x.nrow();
>    NumericVector result = no_init(n);
>
>    for (int r = 0; r < n; r++) {
> result[r] = as<double>(FUN(x(r, _) ) );
>    }
>    return result;
> }
>
>> M <- matrix(1:15, nrow=3);
>> apply(M, 1L, mean)
> [1] 7 8 9
>> rowApply(M, mean);
> [1] 7 8 9
>> identical(rowApply(M, mean), apply(M, 1L, mean));
> [1] TRUE
>
>
> so far so good, with rowApply() is identical to apply(, 1L, ), and the
> speed of rowApply() (in these cases) are faster as measured by benchmark().
>
>
> HOWEVER, when I Rprof() my own project that uses rowApply(), I found a
> lot of time WASTED in calling tryCatch(), tryCatchList(), tryCatchOne(),
> doTryCatch() and evalq().
>
> so, I do this:

Yes. We use tryCatch because we have to fight between C++ and R 
exception models.


If you know your function will not generate an R error, you can use that 
sort of construct to evaluate it without the tryCatch layer :

// [[Rcpp::export]]
NumericVector rowApply(NumericMatrix& x, const Function& FUN){
   int n = x.nrow();
   NumericVector result = no_init(n);

   for (int r = 0; r < n; r++) {
       Language call(FUN, x(r, _)) ;
       result[r] = as<double>(call.fast_eval());
   }
   return result;
}

or more efficiently:

// [[Rcpp::export]]
NumericVector rowApply(NumericMatrix& x, const Function& FUN){
   int n = x.nrow();
   NumericVector result = no_init(n);

   Language call(FUN, R_NilValue) ;
   Language::Proxy proxy( call, 1 );
   for (int r = 0; r < n; r++) {
       proxy = x(r, _) ;
       result[r] = as<double>(call.fast_eval());
   }
   return result;
}

The key here is fast_eval, which just calls R's Rf_eval.

If you go down this road, you have to make sure your function does not 
generate R errors.

Romain


>> debug(tryCatch);
>
> then,
>
>> apply(M, 1L, mean)
> [1] 7 8 9
>
> we see that apply(, 1L, ) runs just fine (without calling things like
> tryCatch() ).
>
>
> UNFORTUNATELY:
>
>> rowApply(M, mean);
> debugging in: tryCatch(evalq(function (x, ...)
> UseMethod("mean")(c(1, 4, 7, 10, 13)), <environment>), error =
> .rcpp_error_recorder)
> debug: {
>      tryCatchList <- function(expr, names, parentenv, handlers) {
>          nh <- length(names)
>          if (nh > 1L)
>              tryCatchOne(tryCatchList(expr, names[-nh], parentenv,
>                  handlers[-nh]), names[nh], parentenv, handlers[[nh]])
>          else if (nh == 1L)
>              tryCatchOne(expr, names, parentenv, handlers[[1L]])
>          else expr
>      }
>      tryCatchOne <- function(expr, name, parentenv, handler) {
>          doTryCatch <- function(expr, name, parentenv, handler) {
>              .Internal(.addCondHands(name, list(handler), parentenv,
>                  environment(), FALSE))
>              expr
>          }
>          value <- doTryCatch(return(expr), name, parentenv, handler)
>          if (is.null(value[[1L]])) {
>              msg <- .Internal(geterrmessage())
>              call <- value[[2L]]
>              cond <- simpleError(msg, call)
>          }
>          else cond <- value[[1L]]
> value[[3L]](cond)
>      }
>      if (!missing(finally))
>          on.exit(finally)
>      handlers <- list(...)
>      classes <- names(handlers)
>      parentenv <- parent.frame()
>      if (length(classes) != length(handlers))
>          stop("bad handler specification")
>      tryCatchList(expr, classes, parentenv, handlers)
> }
> Browse[2]>
> debug: tryCatchList <- function(expr, names, parentenv, handlers) {
>      nh <- length(names)
>      if (nh > 1L)
> tryCatchOne(tryCatchList(expr, names[-nh], parentenv,
>              handlers[-nh]), names[nh], parentenv, handlers[[nh]])
>      else if (nh == 1L)
>          tryCatchOne(expr, names, parentenv, handlers[[1L]])
>      else expr
> }
> Browse[2]>
>
>
> that is, tryCatch() is TRIGGERED !!!
> so, is it the problem of the implementation of rowApply()?
> is there any way around that I could prevent the triggering of tryCatch()?
>
> Many thanks,
> Thomas

-- 
Romain Francois
Professional R Enthusiast
+33(0) 6 28 91 30 30



More information about the Rcpp-devel mailing list