r - Rcpp 函数抱怨未初始化的变量
问题描述
在创建可以使用 Rcpp 从 R 调用的 C++ 函数的第一次尝试中,我有一个简单的函数来使用 Prim 算法从距离矩阵计算最小生成树。此函数已从 ANSI C 的旧版本转换为 C++(运行良好)。
这里是:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
DataFrame primlm(const int n, NumericMatrix d)
{
double const din = 9999999.e0;
long int i1, nc, nc1;
double dlarge, dtot;
NumericVector is, l, lp, dist;
l(1) = 1;
is(1) = 1;
for (int i=2; i <= n; i++) {
is(i) = 0;
}
for (int i=2; i <= n; i++) {
dlarge = din;
i1 = i - 1;
for (int j=1; j <= i1; j++) {
for (int k=1; k <= n; k++) {
if (l(j) == k)
continue;
if (d[l(j), k] > dlarge)
continue;
if (is(k) == 1)
continue;
nc = k;
nc1 = l(j);
dlarge = d(nc1, nc);
}
}
is(nc) = 1;
l(i) = nc;
lp(i) = nc1;
dist(i) = dlarge;
}
dtot = 0.e0;
for (int i=2; i <= n; i++){
dtot += dist(i);
}
return DataFrame::create(Named("l") = l,
Named("lp") = lp,
Named("dist") = dist,
Named("dtot") = dtot);
}
当我在 RStudio 下使用 Rcpp 编译此函数时,我收到两个警告,抱怨变量 'nc' 和 'nc1' 尚未初始化。坦率地说,我无法理解这一点,因为在我看来,这两个变量都在第三个循环中被初始化。另外,为什么没有关于变量“i1”的类似抱怨?
也许不足为奇的是,当尝试从 R 调用这个函数时,使用下面的代码,我得到的是 R 系统的崩溃!
# Read test data
df <- read.csv("zygo.csv", header=TRUE)
lonlat <- data.frame(df$Longitude, df$Latitude)
colnames(lonlat) <- c("lon", "lat")
# Compute distance matrix using geosphere library
library(geosphere)
d <- distm(lonlat, lonlat, fun=distVincentyEllipsoid)
# Calls Prim minimum spanning tree routine via Rcpp
library(Rcpp)
sourceCpp("Prim.cpp")
n <- nrow(df)
p <- primlm(n, d)
这是我用于测试目的的数据集:
"Scientific name",Locality,Longitude,Latitude Zygodontmys,Bush Bush
Forest,-61.05,10.4 Zygodontmys,Cerro Azul,-79.4333333333,9.15
Zygodontmys,Dividive,-70.6666666667,9.53333333333 Zygodontmys,Hato El
Frio,-63.1166666667,7.91666666667 Zygodontmys,Finca Vuelta
Larga,-63.1166666667,10.55 Zygodontmys,Isla
Cebaco,-81.1833333333,7.51666666667 Zygodontmys,Kayserberg
Airstrip,-56.4833333333,3.1 Zygodontmys,Limao,-60.5,3.93333333333
Zygodontmys,Montijo Bay,-81.0166666667,7.66666666667
Zygodontmys,Parcela 200,-67.4333333333,8.93333333333 Zygodontmys,Rio
Chico,-65.9666666667,10.3166666667 Zygodontmys,San Miguel
Island,-78.9333333333,8.38333333333
Zygodontmys,Tukuko,-72.8666666667,9.83333333333
Zygodontmys,Urama,-68.4,10.6166666667
Zygodontmys,Valledup,-72.9833333333,10.6166666667
谁能给我一个提示?
解决方案
如果三个语句之一为真,则永远不会达到nc
和的初始化。您的数据可能无法做到这一点,但编译器无法知道这一点。nc1
if
但是,这不是崩溃的原因。当我运行您的代码时,我得到:
索引越界:[index=1; 范围=0]。
这来自这里:
NumericVector is, l, lp, dist;
l(1) = 1;
is(1) = 1;
声明 a 时NumericVector
,如果要按索引分配值,则必须告知所需的大小。在你的情况下
NumericVector is(n), l(n), lp(n), dist(n);
可能会奏效。您必须仔细分析 C 代码 wrt 内存分配和数组边界。
或者,您可以按原样使用 C 代码并使用 Rcpp 构建包装函数,例如
#include <array>
#include <Rcpp.h>
using namespace Rcpp;
// One possibility for the function signature ...
double prim(const int n, double *d, double *l, double *lp, double *dist) {
....
}
// [[Rcpp::export]]
List primlm(NumericMatrix d) {
int n = d.nrow();
std::array<double, n> lp; // adjust size as needed!
std::array<double, n> dist; // adjust size as needed!
double dtot = prim(n, d.begin(), l.begin(), lp.begin(), dist.begin());
return List::create(Named("l") = l,
Named("lp") = lp,
Named("dist") = dist,
Named("dtot") = dtot);
}
笔记:
- 我返回 a
List
而不是 aDataFrame
因为dtot
是标量值。 - 上面的代码是为了说明这个想法。如果不进行调整,它很可能无法正常工作!
推荐阅读
- ruby-on-rails - Rails slim 将 html 渲染为文本
- jquery - 如何在 jQuery 中使用嵌套的 foreach 循环?
- android - 将 TextView 锚定到 ImageView
- jquery - jQuery ajax 间歇性地失败
- python - 用于验证输入的 Python while 循环
- python - 如何禁用 python asyncio fd 存储?(不要对同一个 FD 感到恐慌)
- java - 命令无效调试@stack队列
- python - 使用python检测firebase实时数据库中的变化
- android - 我的可绘制目录中有许多图像文件。不好吗?
- python - 获取numpy数组中项目的索引,其中值在列表中