我正在开发一个处理3D网格的R包.我有一个构造参数网格的函数,但对于某些参数化,它可以生成重复的顶点(长度为3的数值向量).我需要找到重复的顶点,以便将它们合并为一个顶点.我用Rcpp实现了一个算法来做到这一点.

Rvcg包中有一个用于此的函数:vcgClean(mymesh, sel = 0).它非常快,和它相比,我的C++算法非常慢.类似地,R基函数duplicated的速度要快得多.

以下是我的算法的工作原理.假设有n个顶点.

  • 我取顶点1,将其与顶点2,3,...,n进行比较.

  • 我取顶点2,将其与顶点3,4,...,n进行比较.请注意,如果此顶点已被标记为上一步中顶点1的副本,则可以跳过此比较.我不会那么做的.无论如何,通常会有少量的重复,所以这不是速度慢的原因.

  • 以此类推,将顶点3与顶点4、5、...、n进行比较.

为了比较两个顶点,我测试了每个坐标的近似性:

bool test = nearEqual(v1(0), v2(0)) && nearEqual(v1(1), v2(1)) && nearEqual(v1(2), v2(2));

在此之前,我测试了完全相等,这也很慢.我的nearEqual功能是:

bool nearEqual(double l, double r) {
  return r == std::nextafter(l, r);
}

为什么我的算法这么慢?这是不是因为n-1 + n-2 + ... + 1个比较策略?我不明白我怎么能少做些比较.还是因为nearEqual的功能?不然怎样?顶点存储在Rcpp中的3 x n数值矩阵中.


Edit

我刚刚try 了另一种方法来测试两列的近乎相等,但速度仍然很慢:

const Rcpp::NumericMatrix::Column& v1 = Vertices.column(i);
const Rcpp::NumericMatrix::Column& v2 = Vertices.column(j);
bool test = Rcpp::max(Rcpp::abs(v1 - v2)) < 1e-16;

推荐答案

您可以跟踪在散列map中发现的顶点位置 set中的重复顶点只需执行一次过程:

#include <Rcpp/Lightest>
#include <map>
#include <set>
#include <tuple>

typedef std::tuple<double, double, double> Point3;

// [[Rcpp::export()]]
Rcpp::List duplicated_vertices(Rcpp::NumericMatrix x) {
    std::map<Point3, Rcpp::IntegerVector> positions;
    std::set<Point3> duplicates;

    for (R_len_t i = 0; i < x.ncol(); ++i) {
        Point3 vertex = { x(0, i), x(1, i), x(2, i) };
        if (positions.count(vertex) == 0) {
            Rcpp::IntegerVector position = { i + 1 };
            positions.emplace(vertex, position);
        } else {
            duplicates.insert(vertex);
            positions.at(vertex).push_back(i + 1);
        }
    }

    Rcpp::List result;
    for (const Point3& vertex: duplicates) {
        result.push_back(positions.at(vertex));
    }

    return result;
}

在我的机器上,与duplicated()相比,我获得了大约10倍的加速:

> set.seed(123)
> N <- 150
> M <- matrix(sample(c(1, 2, 3), N * 3, replace = TRUE), 3, N)
> 
> microbenchmark::microbenchmark(
+   Rcpp = dupes(M),
+   R = duplicated(t(M), fromLast = TRUE),
+   cpp_map = duplicated_vertices(M)
+ )
Unit: microseconds
    expr   min     lq    mean median    uq    max neval
    Rcpp 458.7 468.50 490.049  476.6 487.5 1092.7   100
       R 329.2 339.45 408.056  347.6 361.7 5103.3   100
 cpp_map  45.1  47.60  59.972   48.9  52.0  880.7   100

R相关问答推荐

如何判断R中一列的值是否在所有其他列中重复?

指定要保留在wrap_plots中的传奇

即使声明引发错误,R函数也会在第二次try 时返回结果

如何从其他前面列中减go 特定列的平均值?

如何使用geom_sf在边界显示两种 colored颜色 ?

使用sensemakr和fixest feols模型(R)

当两个图层映射到相同的美学时,隐藏一个图层的图例值

为什么在ggplot2中添加geom_text这么慢?

条形图和在Ploly中悬停的问题

用关联字符串替换列名的元素

DEN扩展包中的RECT树形图出现异常行为

比较理论阿尔法和经验阿尔法

有没有办法使用ggText,<;Sub>;&;<;sup>;将上标和下标添加到同一元素?

在多页PDF中以特定布局排列的绘图列表不起作用

列名具有特殊字符时的循环回归

将工作目录子文件夹中的文件批量重命名为顺序

R中治疗序列的相对时间指数

自定义交互作用图的标签

创建新列,其中S列的值取决于该行S值是否与其他行冗余

将文本批注减少到gglot的y轴上的单个值