cvxgrp / CVXR

An R modeling language for convex optimization problems.

Home Page:https://cvxr.rbind.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.