Я думаю, что это хороший пример, чтобы узнать некоторые (основные) материал вызова скомпилированного кода внутри R для ускорения. Здесь я предоставлю функцию C syadd
(симметричная добавка) и ее R-оберточная функция, называемая также syadd
.
/* symmetric add */
/* save this file as "syadd.c"*/
#include <R.h>
#include <Rinternals.h>
SEXP syadd (SEXP N, SEXP V, SEXP compute_diag) {
int n = asInteger(N), diag = asInteger(compute_diag);
/* initialize matrix X as a NA/NaN matrix */
SEXP X = PROTECT(allocVector(REALSXP, n * n));
double *x = REAL(X), *ptr_x = x, *v_end = x + n * n;
while (ptr_x < v_end) *(ptr_x++) = NA_REAL;
/* C interface */
double *v = REAL(V), *vj = v, *vi, *vi_end = v, tmp;
ptr_x = x; v_end = v + n;
if (diag == 1) {
/* compute upper triangular (including diagonal) */
while (vj < v_end) {
tmp = *vj;
ptr_x = x; vi = v;
while (vi <= vi_end) {
*ptr_x = (*vi) * tmp;
vi++; ptr_x++;
}
x += n; vi_end++; vj++;
}
} else {
/* compute upper triangular only */
while (vj < v_end) {
tmp = *vj;
ptr_x = x; vi = v;
while (vi < vi_end) {
*ptr_x = (*vi) * tmp;
vi++; ptr_x++;
}
x += n; vi_end++; vj++;
}
}
UNPROTECT(1);
return X;
}
Чтобы использовать этот код в R, вы должны скомпилировать его в общую библиотеку (.so в Linux или .dll в окнах). Я не знаю, как работать вокруг на Windows, но это, как сделать на Linux:
R CMD SHLIB -c syadd.c
Тогда давайте проверим его в R:
## R wrapper function
syadd <- function (v, diag = TRUE) {
n <- length(v); v <- as.numeric(v); diag <- as.integer(diag)
## load shared library
dyn.load("syadd.so")
X <- .Call("syadd", n, v, diag)
## add "dim" attribute to get a matrix rather than a vector
attr(X, "dim") <- c(n, n)
return(X)
}
Если мы устанавливаем diag = FALSE
, диагональные элементы не вычисляется. Давайте бенчмарк его от R-х base:::outer
:
## benchmarking
v <- 1:10000
system.time(syadd(v,diag = TRUE))
gc()
system.time(outer(v,v,"+"))
gc()
На моем ноутбуке, он принимает 0.97s для syadd
, но 1.91s для outer
. Я думаю, вам нужно разместить мусорную сборку gc()
здесь, так как иначе вы можете поменять местами, что приводит к замедлению.
Комментарии:
- Я только показывает основной способ вызова скомпилированного кода, явным образом с помощью
dyn.load()
. Можно использовать inline
пакет cfunction
. См. Примеры R's C interface - advanced R.
- Было бы хорошо, если бы кто-то мог добавить детали реализации в Windows.
'внешний (v1, v1," + ")'? Если это не так быстро, Rcpp - ваш лучший выбор. – tonytonov
Я думаю, что книга Rcpp имеет вычисления верхнего треугольника как примеры, но моя память может быть неправильной. –