I've just started studying Rcpp and I'm trying to implement PRIM's algorithm. After tons of help and some reading, I have a version that works well, except for simulated data with n=50 or n=1050 (w/ seed 1984).
我刚开始研究Rcpp,我正在尝试实现PRIM算法。在大量的帮助和阅读之后,我有了一个运行良好的版本,除了n=50或n=1050的模拟数据(w/ seed 1984)。
My RStudio throws the "R session Aborted" screen. From the terminal (I'm using Linux Mint 18.3) I get
我的RStudio抛出“R会话中止”屏幕。从终端(我正在使用Linux Mint 18.3)获得
**** Error in `/usr/lib/R/bin/exec/R': double free or corruption (!prev): 0x00000000039f8690 ***
' /usr/lib/R/bin/exec/R': double free or corruption (!prev): 0x00000000039f8690 ***。
After seeking for how to debug my compiled code, I've found:
在寻找如何调试我的编译代码之后,我发现:
-
some material form @Dirk Eddelbuettel explaining about gdb: http://dirk.eddelbuettel.com/papers/rcpp_uzuerich_2015_part5_packaging.pdf
一些材料形式@Dirk Eddelbuettel解释gdb: http://dirk.eddelbuettel.com/papers/rcpp_uzuerich_2015_part5_packaging.pdf
-
some material from @Kevin Ushey explaining about valgrind: http://kevinushey.github.io/blog/2015/04/05/debugging-with-valgrind/
@Kevin Ushey解释valgrind的一些材料:http://kevinushey.github.io/blog/blog/04/05/debugging -with-valgrind/
I've also read about lldb, but decided to go with valgrind.
我也读过关于lldb的文章,但我决定选择valgrind。
I've prepared a cod_valgrind_test.R file in which I generate data and compile my C++ files. All those files are in my github repo (https://github.com/allanvc/test), but I decided to reproduce the code of the problematic file (prim_cpp_bug.cpp) here:
我准备了一个cod_valgrind_test。生成数据并编译c++文件的R文件。所有这些文件都在我的github repo中(https://github.com/allanvc/test),但我决定在这里复制问题文件的代码(prim_cpp_bug.cpp):
#include <iostream>
//#include <Rcpp.h>
#include <RcppArmadillo.h>
//using namespace Rcpp;
//using namespace arma;
using namespace std;
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
Rcpp::List prim_cpp(arma::mat x)
{
int V = x.n_cols;
arma::uvec parent(V);
parent.at(0) = 0;
double max_value = x.max()+1;
int v = 0;
int idxmin_geral = 0;
arma::uvec min_subnot;
arma::mat new_m;
arma::uvec from(V-1);
//from.at(0) = 0;
arma::uvec to(V-1);
for(int i=0; i < V; i++)
{
// "deleting" the row for current vertex by setting the maximum to all entries in this row
x.row(v).fill(max_value); // better than using loop
// insert object x.col(v) at col i of new_m matrix
new_m.insert_cols(i,x.col(v)); //see arma.sourceforge.net
//cout << new_m << endl;
// obtain the minimum index from the selected columns
idxmin_geral = new_m.index_min();
// obtain the subscript notation from index based on reduced dimensions ***
min_subnot = arma::ind2sub(arma::size(new_m.n_rows, new_m.n_cols),
idxmin_geral);
// *** adapted from @coatless
// https://*.com/questions/48045895/how-to-find-the-index-of-the-minimum-value-between-two-specific-columns-of-a-mat
v = min_subnot.at(0);
parent.at(i+1) = v; // -----> !! this is line 61 <-----
to.at(i) = min_subnot.at(0); // -----> !! this is line 63 <-----
from.at(i) = parent.at(min_subnot.at(1)); // -----> !! this is line 64 <-----
// "deleting" the row for current vertex by setting maximum to all entries in this row
// now, in the new matrix
new_m.row(v).fill(max_value); //better than using loop
}
/*
* add 1 to the final vectors - preparing R output
*/
return Rcpp::List::create(
Rcpp::Named("dist",x),
Rcpp::Named("parent",parent),
Rcpp::Named("from",from+1),
Rcpp::Named("to",to+1)
);
}
In my tests, oddly only for n=50 and n=1050 valgrind show me 3 ERRORS when executing the function prim_cpp() from my prim_cpp_bug.cpp file.
在我的测试中,奇怪的是,只有n=50和n=1050 valgrind在执行prim_cpp_bug中的函数prim_cpp()时才会显示3个错误。cpp文件。
Running R -d valgrind -f cod_valgrind_test.R
from terminal returns:
运行R -d valgrind -f cod_valgrind_test。R从终端的回报:
==36904== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
==36904== ERROR SUMMARY: 3个上下文中的3个错误(隐含:0从0)
The problematic lines seem to be:
问题似乎是:
- 61, 63 and 64
- 61年、63年和64年
==36904== Invalid write of size 4 ==36904== at 0x12315F5D: prim_cpp(arma::Mat) (prim_cpp_bug.cpp:61)
== =36904==无效写入大小4== 36904==在0x12315F5D: prim_cpp(arma:::Mat) (prim_cpp_bug.cpp:61)
(...)
(…)
==36904== Invalid write of size 4 ==36904== at 0x12315F63: prim_cpp(arma::Mat) (prim_cpp_bug.cpp:63)
== =36904==无效写入大小4== 36904==在0x12315F63: prim_cpp(arma:::Mat) (prim_cpp_bug.cpp:63)
(...)
(…)
==36904== Invalid write of size 4 ==36904== at 0x12315F74: prim_cpp(arma::Mat) (prim_cpp_bug.cpp:64)
== =36904==无效写入大小4== 36904== 0x12315F74: prim_cpp(arma:::Mat) (prim_cpp_bug.cpp:64)
It seems I'm doing some wrong memory allocation for my vectors - maybe when using indices. I think I’ve read somewhere people not recommending using .at() but I'm not sure. As I don't have enough knowledge about C++ and Rcpp/RcppArmadillo to fix that, I would appreciate any help.
似乎我在为我的向量做一些错误的内存分配——也许在使用索引时。我想我在某些地方读过有人不推荐使用。at(),但我不确定。由于我对c++和Rcpp/RcppArmadillo没有足够的了解,所以我非常感谢您的帮助。
My sessionInfo() is below:
我sessionInfo()如下:
R version 3.4.3 (2017-11-30)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Linux Mint 18.3
Matrix products: default
BLAS: /usr/lib/libblas/libblas.so.3.6.0
LAPACK: /usr/lib/lapack/liblapack.so.3.6.0
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=en_US.UTF-8
[4] LC_COLLATE=en_US.UTF-8 LC_MONETARY=pt_BR.UTF-8 LC_MESSAGES=en_US.UTF-8
[7] LC_PAPER=pt_BR.UTF-8 LC_NAME=C LC_ADDRESS=C
[10] LC_TELEPHONE=C LC_MEASUREMENT=pt_BR.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods base
loaded via a namespace (and not attached):
[1] compiler_3.4.3 tools_3.4.3 yaml_2.1.16
1 个解决方案
#1
3
Since parent
is initialized with V
elements, the indexing is going out of bounds with the last iteration, where i+1
would be V
on line 61 (since indexing starts from 0).
由于父元素是用V元素初始化的,所以索引在最后一次迭代中超出了界限,其中i+1在第61行是V(因为索引从0开始)。
The fact that it doesn't necessarily error for all cases is not a surprise, as in many cases the code will manage to collect some random stuff from memory anyhow. So luckily there were a couple of errors, else the results could simply have been wrong without anyone noticing...
事实上,它不一定在所有情况下都是错误的,这并不令人惊讶,因为在许多情况下,代码将设法从内存中收集一些随机的东西。所以幸运的是出现了一些错误,否则结果很可能是错误的,没有人注意到……
#1
3
Since parent
is initialized with V
elements, the indexing is going out of bounds with the last iteration, where i+1
would be V
on line 61 (since indexing starts from 0).
由于父元素是用V元素初始化的,所以索引在最后一次迭代中超出了界限,其中i+1在第61行是V(因为索引从0开始)。
The fact that it doesn't necessarily error for all cases is not a surprise, as in many cases the code will manage to collect some random stuff from memory anyhow. So luckily there were a couple of errors, else the results could simply have been wrong without anyone noticing...
事实上,它不一定在所有情况下都是错误的,这并不令人惊讶,因为在许多情况下,代码将设法从内存中收集一些随机的东西。所以幸运的是出现了一些错误,否则结果很可能是错误的,没有人注意到……