How to use CVXR variable in Rcpp? The S4 object cannot multiply an int cause an error in Rcpp.
changwn opened this issue · comments
Describe the bug
How to use CVXR variable in Rcpp function?
I have below error when I source cpp file. It is mean the multiply operator '*' is not defined for S4 object and double object. But this is OK in R file.
- no match for 'operator*' (operand types are 'Rcpp::S4' and 'Rcpp::traints::storage_type<14>::type {aka double}')
To Reproduce
The below is the original R code which I want to speed up by using Rcpp. It works good without error.
library('CVXR', warn.conflicts = T)
# Original R code, but two layer for loop is very slow. Thus I decide put for loop in C++ scipt.
# The original R code works good without error.
W = matrix(runif(100),10,10)
y = runif(10)
x = runif(10)
beta_k = Variable(1) #variable
L = 0
for(i in 1:(10-1)){ # time consuming!!!
for(j in (i+1):10)
L = L + W[i, j] * (y[i]-y[j] + beta_k*(x[j]-x[i]) )^2
}
obj = Minimize(L)
problem = Problem(obj)
result = solve(problem)
result$getValue(beta_k)
The below is new R code where 'cal_eqn' replaced for-loop part. The 'cal_eqn' function declared in the below cpp file.
## The below is R code which using a function in C++ file.
library(Rcpp) # load Rcpp first
# source C++ file in order to loading the function.
sourceCpp("cal_L.cpp") #this line will cause error!!!
W = matrix(runif(100),10,10)
y = 21:30
x = 41:50
beta_k = Variable(1)
L = 0
# use this function to replace the for-loop.
L = cal_eqn(L, x, y, W, beta_k) # this line will also cause error!!!
obj = Minimize(L)
problem = Problem(obj)
result = solve(problem)
beta[k] = result$getValue(beta_k)
Below is the cal_L.cpp file.
// create a new file and copy below code into it. Rename this file as 'cal_L.cpp'.
#include <Rcpp.h>
using namespace Rcpp;
// below is for-loop in R file.
// for(i in 1:(10-1)){ # time consuming!!!
// for(j in (i+1):10)
// L = L + W[i, j] * (y[i]-y[j] + beta_k*(x[j]-x[i]) )^2
// }
// [[Rcpp::export]]
double cal_eqn(double L, NumericVector x, NumericVector y, NumericMatrix W, S4 beta_k) {
int len = 10;
for(int i= 0; i<len-1; i++){
for(int j = i+1; j<len; j++){
L = L + W(i, j) * ( y(i)-y(j) + beta_k*(x(j)-x(i)) ) * ( y(i)-y(j) + beta_k*(x(j)-x(i)) );
//int test = W(i, j-1) * ( y(i)-y(j) + (x(j)-x(i)) ) * ( y(i)-y(j) + (x(j)-x(i)) ); // This line prove there is NO other issue except the S4 operator not defined.
}
}
return L;
}
Expected behavior
I search some tutorial about Rcpp. To use S4 object, we should declare the exact slot in S4 object. For CVRX package, the variable has a lot of slot. Which slot I should use or other insight I can try? Thank you in advance.
Version
> sessionInfo()
R version 3.6.0 (2019-04-26)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19041)
Matrix products: default
locale:
[1] LC_COLLATE=English_United States.1252 LC_CTYPE=English_United States.1252 LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C LC_TIME=English_United States.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] Rcpp_1.0.6
loaded via a namespace (and not attached):
[1] compiler_3.6.0
When you mix languages, the execution context is important. In your Rcpp
code, you use:
beta_k*(x(j)-x(i)) )
where the multiply *
is multiplying an S4 object with a constant. That *
is not overloaded, so you have to make a call to the either R's *
or call out to CVXR::multiply(x(j)-x(i), beta_k)
.
@bnaras Thank you so much for your response. I agree with you that the symbol *
is not defined in this situation. CVXR::multiply(x(j)-x(i), beta_k)
is what I want to do in c++ file. Anyway, I already solve my problem in another way on stack overflow.
I will close this issue now and hope this easy example can give some hints to other people. Thank you again.