2012-07-02 1 views
13

я сделал первый удар на функцию Rcpp через inline и решить мою проблему скорости (спасибо Dirk!): R: Replacing negative values by zeroRcpp проход ссылочной VS. по значению

Первоначальная версия выглядела так:

library(inline) 
cpp_if_src <- ' 
    Rcpp::NumericVector xa(a); 
    int n_xa = xa.size(); 
    for(int i=0; i < n_xa; i++) { 
    if(xa[i]<0) xa[i] = 0; 
    } 
    return xa; 
' 
cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp") 

Но при вызове cpp_if(p) он переписал p с выходом, который был не таким, как предполагалось. Поэтому я предположил, что это идет по ссылке.

Так что я установил его с помощью следующей версии:

library(inline) 
cpp_if_src <- ' 
    Rcpp::NumericVector xa(a); 
    int n_xa = xa.size(); 
    Rcpp::NumericVector xr(a); 
    for(int i=0; i < n_xa; i++) { 
    if(xr[i]<0) xr[i] = 0; 
    } 
    return xr; 
' 
cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp") 

Который, казалось, работали. Но теперь оригинальная версия не переписывает свой вклад больше, когда я повторно загрузить его в R (то есть точно такой же код в настоящее время не переписывает его вход):

> cpp_if_src <- ' 
+ Rcpp::NumericVector xa(a); 
+ int n_xa = xa.size(); 
+ for(int i=0; i < n_xa; i++) { 
+  if(xa[i]<0) xa[i] = 0; 
+ } 
+ return xa; 
+ ' 
> cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp") 
> 
> p 
[1] -5 -4 -3 -2 -1 0 1 2 3 4 5 
> cpp_if(p) 
[1] 0 0 0 0 0 0 1 2 3 4 5 
> p 
[1] -5 -4 -3 -2 -1 0 1 2 3 4 5 

Я не единственный, кто попытался повторить это поведение и обнаружили противоречивые результаты:

http://chat.stackoverflow.com/transcript/message/4357344#4357344

Что здесь происходит?

+0

Можете ли вы переформулировать свой вопрос? Вы или не хотите переписывать? Мне кажется, что версия 2 достигает того, что она собирается делать ... Кроме того, есть специальный список рассылки, посвященный Rcpp, где вы, вероятно, получите достойные ответы. –

+0

Пробовал редактировать для ясности. Я не хочу, чтобы он переписывался. Если это неочевидно, я предполагаю, что я должен опубликовать его в списке рассылки, но не хотел бы беспокоить людей в противном случае. –

ответ

18

Они являются «прокси-моделью» - ваш xa действительно является тем же местом памяти, что и исходный объект, поэтому вы в конечном итоге меняете свой оригинал.

Если вы этого не хотите, вы должны сделать одно: (глубокую) копию с использованием метода clone() или, возможно, явное создание нового объекта, в который будет записан измененный объект. Второй метод не, то вы просто используете две разные именованные переменные, которые являются «указателями» (в смысле прокси-модели) исходной переменной.

Дополнительное усложнение, однако, находится в неявным литье и копирование при передаче вектора int (от R) до типа NumericVector: который создает копию, а затем оригинал больше не изменяется.

Вот более явный пример, похожий на один я использую в учебники или семинаров:

library(inline) 
f1 <- cxxfunction(signature(a="numeric"), plugin="Rcpp", body=' 
    Rcpp::NumericVector xa(a); 
    int n = xa.size(); 
    for(int i=0; i < n; i++) { 
    if(xa[i]<0) xa[i] = 0; 
    } 
    return xa; 
') 

f2 <- cxxfunction(signature(a="numeric"), plugin="Rcpp", body=' 
    Rcpp::NumericVector xa(a); 
    int n = xa.size(); 
    Rcpp::NumericVector xr(a);   // still points to a 
    for(int i=0; i < n; i++) { 
    if(xr[i]<0) xr[i] = 0; 
    } 
    return xr; 
') 

p <- seq(-2,2) 
print(class(p)) 
print(cbind(f1(p), p)) 
print(cbind(f2(p), p)) 
p <- as.numeric(seq(-2,2)) 
print(class(p)) 
print(cbind(f1(p), p)) 
print(cbind(f2(p), p)) 

и это то, что я вижу:

[email protected]:~/svn/rcpp/pkg$ r /tmp/ari.r 
Loading required package: methods 
[1] "integer" 
     p 
[1,] 0 -2 
[2,] 0 -1 
[3,] 0 0 
[4,] 1 1 
[5,] 2 2 
     p 
[1,] 0 -2 
[2,] 0 -1 
[3,] 0 0 
[4,] 1 1 
[5,] 2 2 
[1] "numeric" 
     p 
[1,] 0 0 
[2,] 0 0 
[3,] 0 0 
[4,] 1 1 
[5,] 2 2 
     p 
[1,] 0 0 
[2,] 0 0 
[3,] 0 0 
[4,] 1 1 
[5,] 2 2 
[email protected]:~/svn/rcpp/pkg$ 

Так что действительно важно пройти ли вы int-to-float или float-to-float.

+1

Спасибо Дирк. Это говорит мне, как я должен был написать функцию (и я отпишу ее для дальнейшего использования). И я думаю, что имплицитная броска и копия, вероятно, объясняют кажущуюся несогласованность. –

+1

Это головной уборщик, когда вы впервые сталкиваетесь с ним, но да, это имеет смысл. –

+0

Очень интересно. Одно незначительное искажение для ясности: не следует ли переопределять p после каждого вызова функции - в частности, второй вызов f1? В противном случае это измененный p, который подается в f2 ... правильно? –

Смежные вопросы