【问题标题】:Bizarre behavior of Rcpp NumericMatrix when multiplied by scalar on left/rightRcpp NumericMatrix 在左/右乘以标量时的奇怪行为
【发布时间】:2019-12-28 22:47:05
【问题描述】:

谁能解释以下行为?

当声明一个新的NumericMatrixy 作为原始矩阵x 乘以一个标量c 时,标量/矩阵乘法的顺序很重要。如果我将左边的标量和右边的矩阵相乘(例如NumericMatrix y = c * x;),那么我会得到奇怪的行为。原来的矩阵x被改变了!

但是,如果我将原始矩阵放在左边并乘以右边的标量(例如NumericMatrix y = x * c;),x 保持不变。

这似乎不会影响其他数据类型。我已经用intNumericVector 进行了测试。

示例:使用NumericMatrix时出现问题

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericMatrix testfun(NumericMatrix x) {

  NumericMatrix y(x.rows(), x.cols());

  y = x * 2;

  std::cout << x; // x is unmodified

  y = 2 * x; 

  std::cout << x; // x is now modified

  return x;
}



/*** R
x <- matrix(2, nrow = 3, ncol = 3)

print(x)

y <- testfun(x = x)

print(y)

print(x)

*/

输出如下。

> x <- matrix(2, nrow = 3, ncol = 3)

> print(x)
     [,1] [,2] [,3]
[1,]    2    2    2
[2,]    2    2    2
[3,]    2    2    2

> y <- testfun(x = x)
2.00000 2.00000 2.00000
2.00000 2.00000 2.00000
2.00000 2.00000 2.00000
4.00000 4.00000 4.00000
4.00000 4.00000 4.00000
4.00000 4.00000 4.00000

> print(y)
     [,1] [,2] [,3]
[1,]    4    4    4
[2,]    4    4    4
[3,]    4    4    4

> print(x)
     [,1] [,2] [,3]
[1,]    4    4    4
[2,]    4    4    4
[3,]    4    4    4

这是我的会话信息

> sessionInfo()
R version 3.6.1 (2019-07-05)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Catalina 10.15.1

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
[1] compiler_3.6.1            tools_3.6.1               RcppArmadillo_0.9.800.1.0
[4] Rcpp_1.0.2                RcppProgress_0.4.1        packrat_0.5.0            
[7] RcppParallel_4.4.4  

.

【问题讨论】:

  • 我看不出“按引用传递与按值传递”如何成为问题。如果是这样,我希望看到intNumericVector 的行为相同。为什么这只会影响NumericMatrix
  • 为了更简洁地说明这一点,当clone 被传递一个表达式时,使用链接的“答案”中建议的Rcpp::clone 仍然会修改x 作为副作用:@987654341当xRcpp::NumericMatrix 时,@ 修改x。所以我同意这个答案从表面上看是令人满意的。
  • @TommyJones 虽然你不对:int,但我也期待Rcpp::NumericVector;我不认为Rcpp 类的现有讨论(至少不是我见过的讨论)以及通过引用与值传递足以解释用NumericVector 观察到的行为以及它与观察到的对比NumericMatrix 的行为。也许我遗漏了一些东西,但我认为你的问题需要一个新的答案。如果您可以在顶部使用非常简洁的简介来编辑您的问题,解释为什么它与标记的重复项不同(这对您来说应该很容易),这可能会有所帮助
  • 很高兴这样做。明天会有事。
  • 很抱歉我没有更简洁。在我的辩护中,该问题已在顶部说明,第一个示例说明了这一点。 my 问题也解决了。 (我颠倒了乘法的顺序。)我发表这篇文章是为了帮助可能遇到这个问题的其他人。昨天我花了很多时间在 Rcpp 的 GitHub 页面、邮件列表和堆栈溢出上搜索问题,以确保在此处发布问题之前没有得到回答。我很感激你和我一样免费这样做。我昨天花了几个小时回答用户关于我自己的包的问题。 :(

标签: rcpp


【解决方案1】:

这个问题发布得太长了,并且隐藏了它的意义。我们不需要第二个和第三个例子。我们只需要这段代码:

代码

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericMatrix testfun(NumericMatrix x) {
  NumericMatrix y(x.rows(), x.cols());
  y = x * 2;
  std::cout << x; // x is unmodified
  y = 2 * x;      // contrast with x * 2
  std::cout << x; // x is now modified
  return x;
}

/*** R
print(x <- matrix(2, nrow = 2, ncol = 2))
print(y <- testfun(x = x))
print(x)
*/

输出

R> Rcpp::sourceCpp("~/git/stackoverflow/59515517/question.cpp")

R> print(x <- matrix(2, nrow = 2, ncol = 2))
     [,1] [,2]
[1,]    2    2
[2,]    2    2

R> print(y <- testfun(x = x))
2.00000 2.00000
2.00000 2.00000
4.00000 4.00000
4.00000 4.00000
     [,1] [,2]
[1,]    4    4
[2,]    4    4

R> print(x)
     [,1] [,2]
[1,]    4    4
[2,]    4    4
R> 

问题

x * 2 的行为与2 * x 不同。后者有副作用。这可能是一个错误,

更大的问题

用 Rcpp 做矩阵代数并没有什么意义。实施是基本的和不完整的。如果你想做“数学”,请使用 RcppArmadillo 或 RcppEigen。

Arma 实现

#include <RcppArmadillo.h>

// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
arma::mat testfun(arma::mat x) {
  arma::mat y(x.n_rows, x.n_cols);
  y = x * 2;
  std::cout << x; // x is unmodified
  y = 2 * x;      // contrast with x * 2
  std::cout << x; // x is now modified
  return x;
}

/*** R
print(x <- matrix(2, nrow = 2, ncol = 2))
print(y <- testfun(x = x))
print(x)
*/

武装输出

R> Rcpp::sourceCpp("~/git/stackoverflow/59515517/answer.cpp")

R> print(x <- matrix(2, nrow = 2, ncol = 2))
     [,1] [,2]
[1,]    2    2
[2,]    2    2

R> print(y <- testfun(x = x))
   2.0000   2.0000
   2.0000   2.0000
   2.0000   2.0000
   2.0000   2.0000
     [,1] [,2]
[1,]    2    2
[2,]    2    2

R> print(x)
     [,1] [,2]
[1,]    2    2
[2,]    2    2
R> 

我看看能不能解决你在这里找到的 Rcpp 错误。

编辑:这是一个错误,我还不太明白,但我在代码起源的问题上添加了一些内容:https://github.com/RcppCore/Rcpp/issues/365

编辑 2: 修复程序现在在 master 中。感谢 KK 的 PR,感谢其他在 cmets 中暗示这背后的原因的人,尤其感谢 Ralf 让我们所有人尝试修复。

【讨论】:

  • 是的,当我看到这个时,我也查看了Matrix.h,但无法弄清楚为什么顺序(lhsrhs)也很重要。祝你好运……这确实很奇怪!关于使用 Armadillo 的可靠建议
  • Ralf 提出了一个我也考虑过但没有尝试过的修复方法。所以这可能会“很快”被压扁。
  • 我看到了同样的不对称,但没有尝试任何东西,因为我无法推断出它为什么重要。太棒了,它似乎工作了!
  • 同上!我不知道为什么这种变化很重要。 C++ 不好玩吗? ;-)
  • 我也不知道为什么这很重要。这更像是我追求对称性的物理学家;-)
猜你喜欢
  • 2015-04-12
  • 1970-01-01
  • 2023-04-04
  • 2013-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多