Rcpp:*处理NumericMatrix时,*的语法糖会产生意想不到的结果

时间:2014-01-06 13:18:47

标签: r rcpp

A recently asked question让我相信* Rcpp的句法糖不能按预期工作。在链接的问题中,用户试图将矩阵乘以标量。

R代码

以下是我们在Rcpp中尝试实现的目标,但现在只需R

> m <- matrix(0:3, 2, 2)
> m * 3
     [,1] [,2]
[1,]    0    6
[2,]    3    9

Rcpp代码

我已经创建了一些最小的例子,展示了上面的问题,以及一些意想不到的行为。首先请注意,我一直使用List作为返回类型,因为它不需要我提前声明适当的类型:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]

List FooMat() {
  // Create a fill a 2x2 matrix
  NumericMatrix tmp(2,2);
  for (int i = 0; i < 4; i++) {
    tmp[i] = i;
  }

  return List::create(tmp);
}

// [[Rcpp::export]]
List FooMat2() {
  // Create a fill a 2x2 matrix
  NumericMatrix tmp(2,2);
  for (int i = 0; i < 4; i++) {
    tmp[i] = i;
  }

  NumericVector x(1);                                                                                                                                                                                                                      
  x[1] = 3;

  return List::create(tmp * x); 
}

// [[Rcpp::export]]

List FooMat3() {
  // Create a fill a 2x2 matrix
  NumericMatrix tmp(2,2);
  for (int i = 0; i < 4; i++) {
    tmp[i] = i;
  }

  NumericVector x(1);
  x[1] = 3;

  return List::create(tmp * x[1]);
}

// [[Rcpp::export]]

List FooMat4() {
  // Create a fill a 2x2 matrix
  NumericMatrix tmp(2,2);
  for (int i = 0; i < 4; i++) {
    tmp[i] = i;
  }

  return List::create(tmp * 3); 
}

现在,如果我们获取文件,我们会得到一些奇怪的行为:

# Proof that we can return a NumericMatrix in a List:
> FooMat()
[[1]]
     [,1] [,2]
[1,]    0    2
[2,]    1    3

# Multiply the whole NumericMatrix by a whole NumericVector
# whose size is 1. Unsafe behaviour?
> FooMat2()
[[1]]
[1]  0.000000e+00  3.000000e+00 1.388988e-309 2.083483e-309

# Multiply the whole NumericMatrix by the first element of
# The NumericVector. Results are correct, but `*` converts
# the answer to a NumericVector instead of a NumericMatrix
> FooMat3()
[[1]]
[1] 0 3 6 9

# Same as FooMat3() except now we just multiply the NumericMatrix
# by an integer
> FooMat4()
[[1]]
[1] 0 3 6 9

其中,*提供的Rcpp的句法糖似乎不能正确处理矩阵与标量的乘法。二,乘以整数NumericVector,与FooMat2()一样,会导致不安全的行为。

2 个答案:

答案 0 :(得分:4)

正如我在之前的答案中所述,当我需要对矩阵进行实际数学运算时,我使用Armadillo对象:

R> cppFunction('arma::mat scott(arma::mat x, double z) { 
+                 return(x*z); }', 
+              depends="RcppArmadillo")
R> scott(matrix(1:4,2), 2)
     [,1] [,2]
[1,]    2    6
[2,]    4    8
R> 

Sugar操作很好,但不完整。不过,我们肯定会接受补丁。

正如我们之前所说的那样:rcpp-devel是适当的支持渠道。

编辑(2016年10月或2年半后):搜索其他内容让我回到这里。在Rcpp 0.12。*系列中,有些在矩阵和向量之间进行操作时有效,因此基本的“矩阵时间标量”现在可以按照您的预期运行:

R> cppFunction("NumericMatrix testmat(NumericMatrix m, double multme) { 
+               NumericMatrix n = m * multme; 
+               return n; }") 
R> testmat(matrix(1:4,2), 1)
     [,1] [,2]
[1,]    1    3
[2,]    2    4
R> testmat(matrix(1:4,2), 3)
     [,1] [,2]
[1,]    3    9
[2,]    6   12
R> 

我可能仍然会使用RcppArmadillo来计算矩阵数学。

答案 1 :(得分:2)

这是一个糟糕的设计决策的不幸后果,即使Rcpp矩阵来自Rcpp向量。

我可能会在我现在维护的Rcpp实现中恢复这个决定:Rcpp11和Rcpp98。我不再认为让Matrix从Vector派生出来有任何好处,它会妨碍在this file结束时使用的CRTP。