我试图以列表格式对矩阵行进行操作,以计算我正在编写的某些软件的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传递的唯一方法。谢谢你的时间!
答案 0 :(得分:0)
你可以反过来这样做:使用标准的List
(我们知道它通过了),其中每个元素(无论如何必须是SEXP
)都传递了一个Eigen { {1}}(我们也知道单独传递)。
所以我会从简单开始变得更加复杂,直到它破裂。