是否可以将矩阵列表传递给vector <eigen :: map <eigen :: matrixxd>&gt;内联?

时间:2015-09-14 17:58:54

标签: c++ r vector stl rcpp

我试图以列表格式对矩阵行进行操作,以计算我正在编写的某些软件的Hessian矩阵(混合偏导数矩阵)的部分。我发现我只能在R中这么快(即使使用并行化),因此切换到Rcpp以获得更快的速度,并且RcppEigen用于提供的高级矩阵操作。当我依赖List类型来表示从R传递的矩阵/向量列表时,我的Cpp代码随着列表的长度(每个元素是矩阵或向量)的增加而显着减慢。我不确定为什么,但可能是因为动态大小的对象?我的问题是:我可以使用RcppEigen通过类似下面的内容将标准模板库(STL)中的R列表传递到矢量容器中吗?

vector<Eigen::Map<Eigen::MatrixXd>> A(as<vector<Eigen::Map<Eigen::MatrixXd>> >(AA)) 

我想这样做的原因是因为我已经读过访问向量比访问列表要快得多。但是,我可能误解了这一点,如果是这样,我道歉。

这个想法是传入一个向量列表(B2)和一个矩阵列表(A2)。在这些列表的每个索引中,我迭代A2的当前索引中的矩阵(A)的行和B2的当前索引中的向量(b),计算:

b [j] * t(A [j,])%*%A [j,]

表示从0到行-1的j。我最终会得到一个大小等于该索引中矩阵行数的列表,然后转到外部限制的下一个索引,等等。

以下是使用List:

我能够做到的可重复的示例
library(inline)
library(RcppEigen)
library(microbenchmark)    

## Create function which takes list into Rcpp and does all manipulations internally (no lapply outside)
A2 <- lapply(1:2, function(t) matrix(rnorm(10 * t), nrow = t, ncol = 10))
B2 <- lapply(1:2, function(t) rnorm(t))

## This becomes slower relative to R as the size increases.
## Something is not right in how I am programming this.
retLLMat <- "using Eigen::VectorXd;
         typedef Eigen::Map<Eigen::MatrixXd> MapMatd;
         typedef Eigen::Map<Eigen::VectorXd> MapVecd;
         List A(AA), B(BB);
         int listSize = A.size(), ncol, sublistSize;
         List outList;
         double sub;
         for (int i = 0; i < listSize; i++)
         {
           List subList;
           MapMatd subMat(as<MapMatd >(A[i]));
           MapVecd subVec(as<MapVecd >(B[i]));
           ncol = subMat.cols();
           VectorXd currRow(ncol);
           sublistSize = subMat.rows();
           for (int j = 0; j < sublistSize; j++)
           {
             currRow = subMat.row(j);
             sub = subVec[j];
             subList[String(j)] = (sub * currRow) * currRow.transpose();
           }
           outList[String(i)] = subList; 
         }
         return wrap(outList);"

## Compile Cpp code
retLLMatC <- cxxfunction(signature(AA = "List", BB = "List"), retLLMat, plugin = "RcppEigen")
## R version
retLLMat <- function(A, B) mapply(function(a, b) mapply(function(a, b) b * a, lapply(apply(a, 1, function(t) list(tcrossprod(t))), "[[", 1), b, SIMPLIFY = FALSE), A, B, SIMPLIFY = FALSE)

## Test R vs Rcpp version
microbenchmark(retLLMat(A2, B2), retLLMatC(A2, B2))

上面的工作,但是当我将A2和B2的长度增加到接近我在实际实际应用程序中的长度(超过1000)时,Cpp版本相对于R实现减慢并最终变慢。为了克服这个问题,我想到了尝试使用标准模板库矢量格式。我不知道该怎么做,所以我想我开始很简单,只是传递一个List,尝试转换为

vector<Eigen::Map<Eigen::MatrixXd>> 

然后发回R.这就是我尝试过的:

## Testing using a vector of Map<MatrixXd>
## Simplified by trying to return the list after reading it in
VectorMat <- "using Eigen::MatrixXd;
              using std::vector;
              typedef Eigen::Map<Eigen::MatrixXd> MapMatd;
              vector<MapMatd> A(as<vector<MapMatd> >(AA);
              return wrap(A);"

## This produces errors 
test <- cxxfunction(signature(AA = "List"), VectorMat, plugin = "RcppEigen")             

我提前感谢所有人的见解,如果这个问题不适合StackOverflow,请致以诚挚的歉意。我环顾了之前的StackOverflow问题,阅读了发布指南,并且预先用谷歌搜索了一段时间,试图找到我的问题的答案,但似乎我只是在已经问过的范围之外。我非常愿意做出必要的改变,以使这个例子更具可重复性,并使我想做的更清楚。我知道你们都很忙,我不想浪费你的时间。

根据Dirk的建议,我尝试传递一个List,然后定义一个ListOf,鉴于其中的对象的显式特性,它应该更快(如果这是错误的,请纠正我!)

以下是该代码段的内容:

ListMat1 <- "using Eigen::MatrixXd;
typedef Eigen::Map<Eigen::MatrixXd> MapMatd;
ListOf<MapMatd> A(as<ListOf<MapMatd> >(AA));
return wrap(A);"

这通过我的机器传递:

ListMat <- cxxfunction(signature(AA = "List"), ListMat1, plugin = "RcppEigen")
res <- ListMat(A2)

但是,访问此ListOf中的元素似乎仍然存在问题。我知道这通常有效,因为我用数字矢量测试它,即

b2 <- lapply(1:5, function(t) numeric(t))

vecTest <- "ListOf<NumericVector> b(as<ListOf<NumericVector> >(bb)); 
NumericVector res = b[0];
return wrap(res);"   

vecTestfn <- cxxfunction(signature(bb = "List"), vecTest, plugin = "RcppEigen")
vecTestfn(b2)

如果我尝试用ListOf做同样的事情,其中​​每个元素都是MatrixXd,我似乎有一个问题:

ListMatInd <- "using Eigen::MatrixXd;
typedef Eigen::Map<Eigen::MatrixXd> MapMatd;
ListOf<MapMatd> A(as<ListOf<MapMatd> >(AA));
MatrixXd res = A[0];
return wrap(res);"

这会在尝试时产生错误:

ListMatIndfn <- cxxfunction(signature(AA = "List"), ListMatInd, plugin = "RcppEigen")

我会继续尝试。我只想更新我现在的位置。此时,在完全阅读Rcpp书籍之前(我将用我的个人开发基金订购),这是我知道将列表中的每个元素作为特征映射MatrixXd传递的唯一方法。谢谢你的时间!

1 个答案:

答案 0 :(得分:0)

你可以反过来这样做:使用标准的List(我们知道它通过了),其中每个元素(无论如何必须是SEXP)都传递了一个Eigen { {1}}(我们也知道单独传递)。

所以我会从简单开始变得更加复杂,直到它破裂。